Git Product home page Git Product logo

reason-react's People

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  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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reason-react's Issues

The value ++ can't be found

Hi,
I am trying out ReasonML. Did the global installation and bs-platform.
Created the ap using bsb -init my-first-app -theme basic-reason.
But when i try out the examples i get error above.
example: let x = "Hello" ++ "World";

`> [email protected] start /Users/prashanth/workspace/reasonml/my-first-app

bsb -make-world -w

Start compiling
Rebuilding since just get started
ninja: Entering directory lib/bs' ninja: no work to do. Finish compiling Start compiling Rebuilding since [ [ 'change', 'demo.re' ] ] ninja: Entering directory lib/bs'
[2/2] Building src/demo.mlast.d
[1/1] Building src/demo-MyFirstApp.cmj
FAILED: src/demo-MyFirstApp.cmj /Users/prashanth/workspace/reasonml/my-first-app/lib/js/src/demo.js src/demo-MyFirstApp.cmi
/usr/local/lib/node_modules/bs-platform/bin/bsc.exe -bs-package-map my-first-app -bs-package-output commonjs:lib/js/src -bs-assume-no-mli -bs-no-builtin-ppx-ml -bs-no-implicit-include -I . -I src -w -30-40+6+7+27+32..39+44+45+101 -nostdlib -I '/Users/prashanth/workspace/reasonml/my-first-app/node_modules/bs-platform/lib/ocaml' -no-alias-deps -color always -bs-re-out -bs-super-errors -o src/demo-MyFirstApp.cmj -c src/demo.mlast

We've found a bug for you!
(No file name)

The value ++ can't be found

ninja: build stopped: subcommand failed.

Finish compiling(exit: 1)
`

`willMount` for server side rendering

In React Server side rendering, componentDidMount is not triggered.
On the other hand, ReasonReact doesn't have willMount but only didMount.

What can I do if I need componentDidMount in server side?

Bug with reducer when one action triggers second one in its side effects and second one has side effects

Component example to reproduce the behavior

type state = unit;
type actions = | A | B;

let component = ReasonReact.reducerComponent "Test";

let make _ => {
  ...component,
  initialState: fun () => (),
  reducer: fun action _state => switch action {
    | A => {
      Js.log "A action triggered";
      ReasonReact.SideEffects (fun { reduce } => {
        Js.log "A side effects triggered";
        /* Doesn't work as expected */
        reduce (fun _ => B) ();
        /* Works as expected */
        /* Js.Global.setTimeout (fun _ => {
          reduce (fun _ => B) ();
        }) 0
        |> ignore; */
      })
    }
    | B => {
      Js.log "B action triggered";
      ReasonReact.SideEffects (fun _ => {
        Js.log "B side effects triggered"
      })
    }
  },
  render: fun self => {
    let _state: unit = self.state;
    <div>
      <button onClick=(self.reduce (fun _ => A))>(ReasonReact.stringToElement "Trigger A")</button>
      <button onClick=(self.reduce (fun _ => B))>(ReasonReact.stringToElement "Trigger B")</button>
    </div>
  }
}

When you trigger action B directly it works correctly.

When you trigger action A it triggers both console logs from action A and the first one from action B, but B's side effects are never triggered.

Also on react 15, when you click A, then the B action's first console log will only get triggered on the next action. So when you press A you'd get logs

A action triggered
A side effects triggered

And when you press A again all console logs become (same kind of behavior on triggering A and then B)

A action triggered
A side effects triggered
B action triggered
A action triggered
A side effects triggered

So the B action is only handled when next action is triggered (but before it) and side effects are still ignored.

When you add timeout to triggering action B it all works as expected

Versions:
bs-platform 1.9.3
reason-react 0.2.4
OS: Ubuntu 16.04

Cross-platform style

Carried over from reasonml-old/reason-react#79. cc @saschatimme

Reason React currently defines style in ReactDOMRe. In bs-react-native we have also defined styles.

Now we have a problem if some component is cross-platform (e.g. react-navigation) and takes style as a prop (for which style would you write the bindings?).

I would propose to move the style type from ReactDOMRe to ReactRe. Then we could use the same style in both projects.

start using Semver

since npm expects semver it reduces the chance of new version breaking a build

Component children warning

let comp = ReasonReact.statelessComponent "Container";

let make children => {
  ...comp,
  render: fun _ => <div> (children |> ReasonReact.arrayToElement) </div>
};

Will raise

Warning: Each child in an array or iterator should have a unique "key" prop.

in Chrome console.

Provide an alternative API for props that uses structs instead of named parameters

In react-react, I have an abstraction on creating ReasonReact components. Each component looks like the following:

module FooComponent = {
    type props = {name: string};
    let vdomS propsS => S.map eq::(fun _ _ => false)
        (fun {name} => <p> (ReasonReact.stringToElement name) </p>) propsS;
    let component = ReasonReact.reducerComponent "FooComponent";
    let make ::name _children => ReasonReact.componentFromSignal component {name} vdomS;
};

So, there's always 3 user-provided parameters:

  1. a type (which will be used to pass the props to the signal
  2. a signal (which will really model how the component will work)
  3. a component name (which will be passed to ReasonReact.reducerComponent)

If this could be a functor, so I could abstract my API even further to look like this:

module FooComponent = GenerateComponent {
    let name = "FooComponent";
    type props = {name: string};
    let vdomS propsS => S.map eq::(fun _ _ => false)
        (fun {name} => <p> (ReasonReact.stringToElement name) </p>) propsS;
};

And the rest would be "magic".

But make can't be generalized like that. Each make function that takes different props will have completely different type signatures from each other.

But if JSX could look for a make_ function that, instead of using named parameters, used structs (optional parameters would be represented by fields with the option type, of course), I could implement GenerateComponent like the following:

module type COMPONENT = {
    open ReactFrp.React;
    let name: string;
    type props;
    let vdomS: signal props => signal ReasonReact.reactElement;
};

module GenerateComponent(C: COMPONENT) => {
    let component = ReasonReact.reducerComponent C.name;
    let make_ (props: C.props) _children => ReactReact.componentFromSignal component props C.vdomS;
};

Surely this would benefit more libraries than just react-react. Everyone who wants to abstract away details in the creation of a ReasonReact component could benefit from it. So, do you think the proposal makes sense?

Event type assumption on handlers is not always correct

Currently when you select something in a dropdown component, reason-react event handler expects to receive "event" object of type reactEventRe to kinda emulate JS event object. But third-party library can not always return event object, but just values.
So in JS words, for example
instead of this
const onClick = (e) => e;
return
const onClick = (e) => e.target.value;
So then all this assumption on reason-react of getting event type makes it impossible to use without hacks.

Example:

https://raw.githubusercontent.com/acierto/ts-explorer/master/src/core/advancedFilter/advancedFilter.re lines 28-29.

screen shot 2017-08-12 at 11 51 57

I'm receiving back from react-select lib onChange event with data {value: 'bla', 'label': bla}. But reason-react expects there reactEventRe type. So I don't know another hack as only by means of JS interops map type to my structure.

screen shot 2017-08-12 at 11 51 47

This project works, so you can easily reproduce that problem there.

Add support for React context

From the ReasonReact docs:

ReasonReact doesn’t support ReactJS context (yet).

What needs to take place in order for ReasonReact to support context? Are we waiting for the context API to become stable before adding in support for it?

InitialState Object not working

This is working:

let component = ReasonReact.statefulComponent "Greeting";
let make _children => {
  ...component,
  initialState: fun () => "", 
  render: fun self => {
      <div> (ReasonReact.stringToElement ( self.state)) </div>
    }
};

This is not:

let component = ReasonReact.statefulComponent "Greeting";

type state = {
    inputText: string
};

let make _children => {
  ...component,
  initialState: fun () => {
    inputText: ""
  }, 
  render: fun self => {
      <div> (ReasonReact.stringToElement ( self.state.inputText)) </div>
    }
};

namespace for dom elements that's agnostic to reasonreact

Aka it'd be nice if <div /> post-ppx compiled to something like DOM.createElement("div", ...) rather than ReactDOMRe.createElement("div", ...). It's only a name change; but this allows alternatives such as Preact to override the DOM part without giving the impression that these are from ReasonReact.

Technically you could just use the pre-ppx desugared JSX: https://reasonml.github.io/guide/language/jsx

but writing one's own ppx + distribute it for js compilation isn't straightforward yet, and discouraged (macros and all)

Links going to a 404 with props-spread

Both in docs/props-spread.md and in docs/clone-element.md there is a dead link to props-spread, is this section deliberately removed from the docs? Or has just been moved? If that is the case, I would really want to prove a PR helping to fix the docs! πŸ˜„

[Website] Paragraphs are way too wide.

Most recommendations put the optimal line length at 45-75 characters (See this for example). The line length in the docs are currently about 2-3 times as long at 120+ characters, making it a bit to read.

Type error in place of action type error

When the action type is defined after the component, it will give the error:

Is this a ReasonReact component with state?
  If so, is the state type declared _after_ the component declaration?
  Moving the state type before the declaration should resolved this!

It should be

Is this a ReasonReact component with state?
  If so, is the state or action type declared _after_ the component declaration?
  Moving the state and action type before the declaration should resolved this!

Document Common Errors

Here are some I made :D

  • a make function that just returns jsx (not the component spread)
  • a make function that doesn't have a final _children arg (the error is super inscrutable)

ES6 output is broken for Rollup compilation/tree shaking

When trying to compile Reason React with Rollup, the error

Error: Cannot call a namespace ('CreateClassInternalHack')

is thrown when compiling reason-react/lib/es6/src/reasonReact.js

import * as CreateClassInternalHack from "create-react-class";

is the problem, because trying to import the module's exports with import *, but create-react-class is not a real ES6 module, and only exports a function. When CreateClassInternalHack is called as a function, that's invalid as the result of import * should be an object.

Instead the import should ideally just import the default export:

import CreateClassInternalHack from "create-react-class";

However it might be difficult to get BuckleScript to produce this output. An alternative might be to define a wrapper JS module for create-react-class which exports this function in a way which is compatible with the import that BuckleScript produces.

[Docs] Is there a tutorial similar to Angular's "Tour of Heroes"?

πŸ‘‹ Not sure if this is the right place to put this, but I'm just starting to use reason-react and I feel like a guided tutorial would be a nice way of getting introduced to the ecosystem.

Angular has this really nice Tour of Heroes tutorial. It's is a relatively comprehensive guide that goes through a lot of the Angular core and its best practices. I'm not very familiar with react-reason (or reasonml in general) and I'm wondering if something like the Tour of Heroes exists or if someone is working on something similar. If not, I'd love to star this effort.

Improve debugability of reason component props

Copied from reasonml-old/reason-react-example#21 (wrong place)


Reading the ReasonReact.re module has been enlightening as to how to create type safe bindings to a fairly complex and dynamic javascript library. Definitely awesome work by the team to get this far (and make the interface extremely simple and flexible).

I have done an experiment with part of my companies code base that shows that Reason can be trivially integrated and used to provide type safety to our react components. As part of the feedback of this experiment, one of my colleagues asked how to debug a Reason components props?

While the bucklescript output is easy to add breakpoints to, there are also other tools that can help debug a react component, particularly in more complex scenarios. I am talking specifically about the React Developer Tools for Chrome specifically: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi , but I am sure there are other tools that make use of the react library to provide other information that can help a user of react identify problem components.

I have attached some screenshots of how Reason components are rendered in the React Developer Tools for the snippet of Reason posted below, and as should be evident, the debugability of the FA component much lower than that of the LikeStatus component, primarily because the reason props are opaque to the rest of the system.

module FontAwesome = {
  let component = ReasonReact.statelessComponent "FA";
  let make name::name _children => {
    ...component,
    render: fun () _ => {
      <i className={"icon fa fa fa-" ^ name} />
    }
  };
};

let component = ReasonReact.statelessComponent "LikeStatus";
let make numLikes::numLikes ::isLiked ::canLike _children => {
  ...component,
  render: fun () _ => {
    ReactDOMRe.createElement "like-status" [|
      <span className="num-likes">{ReactRe.stringToElement (string_of_int n ^ " people like this")}</span>,
      if isLiked {
        <span className="unlike">
          <FontAwesome name="thumbs-up" />
          <span>{ReactRe.stringToElement "Unlike"}</span>
        </span>
      } else {
        /* !isLiked */
        if canLike {
          <span className="like">
            <FontAwesome name="thumbs-o-up" />
            <span>{ReactRe.stringToElement "Like"}</span>
          </span>
        } else {
          ReactRe.nullElement
        }
      }
    |]
  }
};

let comp =
  ReasonReact.wrapReasonForJs
    ::component
    (fun jsProps =>
      make
        numLikes::jsProps##numLikes
        isLiked::(Js.to_bool jsProps##isLiked)
        canLike::(Js.to_bool jsProps##canLike) [||]
    )

screen shot 2017-06-23 at 12 00 22 pm

I propose a debugProps feature in componentSpec where a component can return what it considers to be it's props as a Js object that is merged with the props next to "reasonProps" (specifically here:

component.reactClassInternal props::{"key": key, "ref": ref, "reasonProps": element} [||]
), It won't be as fool proof as the debugability of the rest of the react ecosystem, but it gives us a backdoor into inspecting the prop arguments that are given to our components make functions.

Let me know what you think.

Props don't get updated for custom event handelrs

Given this (heavily reduced) component:

  let make ::count ::onChange _children => {

    let handleClick _ => {
      onChange (count + 1)
    };

    {
      ...component,

      didMount: fun self => {
        /* assume `element` has been acquired by legit means */
        element##addEventListener "click" handleClick;
        ReasonReact.NoUpdate
      },

      render: fun self =>
         ...
    }
  };

onChange will never be called with anything other than 1, regardless of what the count prop is changed to. The reason is of course that make will be called again on props change, which will define a new handleClick function that closes over the new prop value, but will not (and obviously should not) call didMount again to attach the updated event handler. So the old event handler with the old prop value will be called in perpetuity.

This isn't all that surprising if you understand how RR actually works, but it is if you expect it to work like reactjs' this.props (which of course I did, even though I should know better). RR creates the illusion, and thereby expectation, that it does work like this.props, until of course it doesn't. I suggest that this is made clear in the documentation somewhere, even if just as a FAQ.

There are two workarounds, neither of which are very nice:

  1. Copy the prop to state (or retainedProps?), and use state in the event handler instead.
  2. Remove and re-attach the event handler on didUpdate. This would also involve maintaining state to keep a reference of the currently attached event handler for removal, but is a more contained solution and good practice regardless of needing updated props, in case the element is re-inserted.

This seems like a fundamental restriction with the API as it currently is, but I wanted to bring it up so perhaps it can be addressed in some future iteration at least.

Full example here: https://github.com/glennsl/rr-stale-props-issue/blob/abb81215857d4240b5bfd748dbb28e4d98590d33/src/index.re

Better DOM.render method

Unifies render, renderToElementWithClassName and renderToElementWithId

  type containerType = [ | `element(Dom.element) | `className(string) | `id(string)];
  let render = (reactElement, container: containerType) =>
    switch container {
    | `element(element) => _render(reactElement, element)
    | `className(className) =>
      switch (getElementsByClassName(className)) {
      | [||] =>
        raise(
          Invalid_argument(
            "ReasonReact.DOM.render: no element of class " ++ className ++ " found in the HTML."
          )
        )
      | [|element|] => _render(reactElement, element)
      | elements => _render(reactElement, elements[0])
      }
    | `id(id) =>
      switch (getElementById(id)) {
      | None =>
        raise(
          Invalid_argument(
            "ReasonReact.DOM.render: no element of id " ++ id ++ " found in the HTML."
          )
        )
      | Some(element) => _render(reactElement, element)
      }
    };

Poly variants might be beginner unfriendly until we document them clearly.
Normal variants aren't that friendly because you need to qualify them.

Update docs for interop with ES6 modules

Creating this issue by the request of @chenglou from the following discussion we had on discord:

image

The docs here and here only show how to interop with ES5 modules.

If you guys would like I'd be happy to submit a PR updating these docs, let me know

Document subscription patterns

We should look into first-classing as much as possible here, but once we've gotten to where we are comfortable we should document how deal with various sub/release apis. They very widely and some are more friendly to our React patterns than others.

Enable simple "middleware" for actions/reducers

πŸ‘ on the new reducer API, it looks great!

One use-case from Redux that I would love to see enabled is centralized logging of actions; it can be tremendously useful for debugging. In Redux the way to do this is with a logging middleware, a generic function that all actions pass through on their way to the reducer. Analytics are another widely useful application for middleware, and this API could potentially allow actions to be transformed on their way through the middleware.

In Discord, @rickyvetter suggested adding an optional reducerHook argument when creating a component. Then you could create your own component "factory" as follows:

let awesomeLogger action => {
  Js.log action;
  action
}

let reducerComponentWithAwesomeLogging
    debugName
    :componentSpec 'state stateless noRetainedProps noRetainedProps 'action =>
  basicComponent reducerHook::awesomeLogger debugName;

Obviously logging a plain variant with Js.log as above is not going to be super useful, it's just there to show the concept and a potential action => action middleware signature

Type error: array of object expected array of ReasonReact.reactElement

I've seen it's a common type error, but the link to the solution isn't clear:
https://reasonml.github.io/reason-react/index.html#reason-react-working-with-children

This was causing my error
<RenderList todos/> (type state { todos: list todo })
but if I replace it with RenderList.make todos children I have the following error:
Type todo is not compatible with type string that seem to be because of my RenderList component :
let make ::todos _children => { /**/} Can I type the todos here?

Another error I have is when I embed the component in other DOM elements:

render: fun => {
  <div>
    (RenderList.make todos children)
  </div>
}

I get the error: Unbound module RenderList

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.