GithubHelp home page GithubHelp logo

github-reason-react-tutorial's Introduction

reason-repo-list

Run Project

npm install
npm start
# in another tab
npm run webpack

After you see the webpack compilation succeed (the npm run webpack step), open up build/index.html (no server needed!). Then modify whichever .re file in src and refresh the page to see the changes.

For more elaborate ReasonReact examples, please see https://github.com/reasonml-community/reason-react-example

Run Project with Server

To run with the webpack development server run npm run server and view in the browser at http://localhost:8000. Running in this environment provides hot reloading and support for routing; just edit and save the file and the browser will automatically refresh.

Note that any hot reload on a route will fall back to the root (/), so ReasonReact.Router.dangerouslyGetInitialUrl will likely be needed alongside the ReasonReact.Router.watchUrl logic to handle routing correctly on hot reload refreshes or simply opening the app at a URL that is not the root.

To use a port other than 8000 set the PORT environment variable (PORT=8080 npm run server).

Build for Production

npm run clean
npm run build
npm run webpack:production

This will replace the development artifact build/Index.js for an optimized version as well as copy src/index.html into build/. You can then deploy the contents of the build directory (index.html and Index.js).

If you make use of routing (via ReasonReact.Router or similar logic) ensure that server-side routing handles your routes or that 404's are directed back to index.html (which is how the dev server is set up).

To enable dead code elimination, change bsconfig.json's package-specs module from "commonjs" to "es6". Then re-run the above 2 commands. This will allow Webpack to remove unused code.

github-reason-react-tutorial's People

Contributors

jsdf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

github-reason-react-tutorial's Issues

Dont Repeat Yourself/Open Helper

At the Don't Repeat Yourself/ open helper section of your demo. The following proposed code throws an error:

let parseRepoJson = (json: repo) =>
  Json.Decode.{
    full_name: field("full_name", string, json),
    stargazers_count: field("stargazers_count", int, json),
    html_url: field("html_url", string, json)
  };

-error:

./src/index.re
Module build failed: Error: We've found a bug for you!
  /Users/shingdev/code/REASON/reason-repo-list/src/RepoData.re 29:41-44

  27 │ let parseRepoJson = (json: repo) =>
  28 │ Json.Decode.{
  29 │   full_name: field("full_name", string, json),
  30 │   stargazers_count: field("stargazers_count", int, json),
  31 │   html_url: field("html_url", string, json)

  This is:
    repo
  But somewhere wanted:
    at <anonymous>ined as Js.Json.t)

Adding back the Js.Json.t from the original verbose example makes the error go away.

let parseRepoJson = (json: Js.Json.t): repo =>
 Json.Decode.{
  full_name: field("full_name", string, json),
  stargazers_count: field("stargazers_count", int, json),
  html_url: field("html_url", string, json)
};

Not sure if this is what you intended.

Example upto/before reducerComponent Heading doesnt run

Might not be supposed to run at this point...

This, i think, is the code up to that point:


/* define type for state
Note that the state type must be defined before the call
to ReasonReact.reducerComponent or you'll get an error
saying something like "The type constructor state would
escape its scope". Since RepoData might be null and we need to account for
that type as a possibility, we have to use Reason's option type,
then in initialstate wrap our record in Some() to let compiler no that this might be a data
or null. The option type as to variants, Some or None. Some when a value is present
None when no value is present.
*/

type state = {repoData: option(RepoData.repo)};

let component = ReasonReact.reducerComponent("App");

let dummyRepo: RepoData.repo = {
  stargazers_count: 27,
  full_name: "jsdf/reason-react-hackers-news",
  html_url: "https://github.com/jsdf/reason-react-hacker-news"
};

/* use switch statement instead of render on initialState so that we can 
account for each result in our repo data option type, the render that arg
in the div. RepoItem module expects a repo, so Some gives us a repo, pass that
value to RepoItem ~repo named arg.
*/
let make = (_children) => {
  ...component,
  initialState: () => {
    repoData: Some(dummyRepo)
  },
  render: (self) => {
    let repoItem =
      switch (self.state.repoData) {
      | Some(repo) => <RepoItem repo=repo />
      | None => ReasonReact.stringToElement("Loading")
      };
    <div className="App">
      <h1>{ReasonReact.stringToElement("Reason Projects")}</h1>
      repoItem
    </div>
  }
};

it produces this error:

./src/index.re
Module build failed: Error: We've found a bug for you!
  /Users/shingdev/code/REASON/reason-repo-list/src/app.re 15:17-51
  
  13 │ type state = {repoData: option(RepoData.repo)};
  14 │ 
  15 │ let component = ReasonReact.reducerComponent("App");
  16 │ 
  17 │ let dummyRepo: RepoData.repo = {
  
  Is this a ReasonReact reducerComponent or component with retained props?
  If so, this error will disappear after:
  - Defining the component's `make` function
  - Using the state once or annotating it with a type where it's used (e.g. render)
  - Doing the same for action (in e.g. reducer)
  - Doing the same for retained props, if any
  
  Here's the original error message
  This expression's type contains type variables that can't be generalized:
  ReasonReact.componentSpec
  (state,  ReasonReact.stateless,  ReasonReact.noRetainedProps, 
    ReasonReact.noRetainedProps,  '_a)
  
  This happens when the type system senses there's a mutation/side-effect, in combination with a polymorphic value.
  Using or annotating that value usually solves it. More info:
  https://realworldocaml.org/v1/en/html/imperative-programming-1.html#side-effects-and-weak-polymorphism    at <anonymous>

Typo in your blog?

You have this:

    let repoItem =
      switch (self.state.repoData) {
      | Some(repo) => <RepoItem repo=repo />
      | None => ReasonReact.stringToElement("Loading")
      };
    <div className="App">
      **<h1>{ReasonReact.stringToElement("Reason Projects")</h1>**
      repoItem
    </div>
  }
  • should be this?
render: (self) => {
    let repoItem =
      switch (self.state.repoData) {
      | Some(repo) => <RepoItem repo=repo />
      | None => ReasonReact.stringToElement("Loading")
      };
    <div className="App">
      **<h1>{ReasonReact.stringToElement("Reason Projects")}</h1>**
      repoItem
    </div>
  }

Data array not updating

Another thing is that the examples using data array are showing "loading" in the browser but never update with the data. This is the code I have that is doing that:


type state = {repoData: option(array(RepoData.repo))};

type action =
  | Loaded(array(RepoData.repo));

let component = ReasonReact.reducerComponent("App");

/* make dummy repos an array using Reason array literal syntax,
define a string of JSON and use it with parseRepoJson() from RepoData.re.
`{js| ... |js}` is an alternative form of reason string literal syntax.
*/
 
let dummyRepos: array(RepoData.repo) = [|
  RepoData.parseRepoJson(
    Js.Json.parseExn(
      {js|
        {
          "stargazers_count": 93,
          "full_name": "reasonml/reason-tools",
          "html_url": "https://github.com/reasonml/reason-tools"
        }
      |js}
    )
  )
|];

/* use switch statement instead of render on initialState so that we can 
account for each result in our repo data option type, the render that arg
in the div. RepoItem module expects a repo, so Some gives us a repo, pass that
value to RepoItem ~repo named arg.
*/
let make = (_children) => {
  ...component,
  initialState: () => {
    repoData: None
  },
  reducer: (action, state) => {
    switch action {
      | Loaded(loadedRepo) =>
        ReasonReact.Update({
          repoData: Some(loadedRepo)
        })
    }
  },
  render: (self) => {
    let repoItem =
    switch (self.state.repoData) {
    | Some(repos) => ReasonReact.arrayToElement(
        Array.map(
          (repo: RepoData.repo) => <RepoItem key=repo.full_name repo=repo />,
          repos
        )
    )
    | None => ReasonReact.stringToElement("Loading")
    };
  
    <div className="App">
      <h1>{ReasonReact.stringToElement("Reason Projects")}</h1>
      {repoItem}
    </div>
  }
};

getting this warning in devtools

Warning number 27
  /Users/shingdev/code/REASON/reason-repo-list/src/app.re 38:21-25
  
  36 ┆   repoData: None
  37 ┆ },
  38 ┆ reducer: (action, state) => {
  39 ┆   switch action {
  40 ┆     | Loaded(loadedRepo) =>
  
  unused variable state.

How would this work with ReasonReact.SideEffects

Love the tutorial. However I've been looking around for how to handle side effects properly with reducer components and can't find much information. A scenario being if we had a button that loaded the next page. In js react land you might trigger an action that does a side effect that optionally does a state changes along the way.

The flow would be

  1. dispatch action
  2. reducer doesn't do anthing with action (NoUpdate)
  3. Middleware handles the action allowing for more actions to be dispatched and side effects to fetch data or do some other work

Tools that promote this pattern:
-https://github.com/redux-saga/redux-saga
-https://github.com/redux-observable/redux-observable

How would you handle doing a side effect from an event, like the click load more example above?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.