Git Product home page Git Product logo

react-tree-walker's Introduction

Update

I haven't been focusing on this library as I tend to reach for Next.js for my SSR needs. If anyone is interested in maintaining the library further I am happy to add you as a collaborator to the project.

As an alternative I can highly recommend react-ssr-prepass, developed by @kitten of Formidable Labs, which provides the same functionality with built in support for suspense.

Disclaimer

This library does not operate in an idiomatic manner against React. It makes some assumptions about the internals of React and makes calls against Components directly. This is a risk as it likely to break with future releases of React, i.e. the upcoming Suspense release.

Personally, I've found this library helpful in providing me with a solution for my server side rendering data fetching needs. That being said I very much look forward to being able to move over to Suspense as soon as it is stable and avoid having to use hacks/workarounds such as this library.

Please consider carefully before adopting this library. If you are happy to take on the risk I would recommend you write an abstraction over it that will allow you to easily remove/replace it from your codebase with Suspense or another more idiomatic solution.


react-tree-walker 🌲

Walk a React (or Preact) element tree, executing a "visitor" function against each element.

npm MIT License Travis Codecov

TOCs

Introduction

Inspired/lifted from the awesome react-apollo project. 😗

This modified version expands upon the design, making it Promise based, allowing the visitor to return a Promise, which would subsequently delay the tree walking until the Promise is resolved. The tree is still walked in a depth-first fashion.

With this you could, for example, perform pre-rendering parses on your React element tree to do things like data prefetching. Which can be especially helpful when dealing with declarative APIs such as the one provided by React Router 4.

Illustrative Example

In the below example we will create a visitor that will walk a React application, looking for any "class" component that has a getData method on it. We will then execute the getData function, storing the results into an array.

import reactTreeWalker from 'react-tree-walker'

class DataFetcher extends React.Component {
  constructor(props) {
    super(props)
    this.getData = this.getData.bind(this)
  }

  getData() {
    // Supports promises! You could call an API for example to fetch some
    // data, or do whatever "bootstrapping" you desire.
    return Promise.resolve(this.props.id)
  }

  render() {
    return <div>{this.props.children}</div>
  }
}

const app = (
  <div>
    <h1>Hello World!</h1>
    <DataFetcher id={1} />
    <DataFetcher id={2}>
      <DataFetcher id={3}>
        <DataFetcher id={4} />
      </DataFetcher>
    </DataFetcher>
    <DataFetcher id={5} />
  </div>
)

const values = []

// You provide this! See the API docs below for full details.
function visitor(element, instance) {
  if (instance && typeof instance.getData) {
    return instance.getData().then(value => {
      values.push(value)
      // Return "false" to indicate that we do not want to visit "3"'s children,
      // therefore we do not expect "4" to make it into our values array.
      return value !== 3
    })
  }
}

reactTreeWalker(app, visitor)
  .then(() => {
    console.log(values) // [1, 2, 3, 5];
    // Now is a good time to call React's renderToString whilst exposing
    // whatever values you built up to your app.
  })
  // since v3.0.0 you need to do your own error handling!
  .catch(err => console.error(err))

Not a particularly useful piece of code, but hopefully it is illustrative enough as to indicate the posibilities. One could use this to warm a cache or a redux state, subsequently performing a renderToString execution with all the required data in place.

Order of Execution

react-tree-walker walks your React application in a depth-first fashion, i.e. from the top down, visiting each child until their are no more children available before moving on to the next element. We can illustrate this behaviour using the below example:

<div>
  <h1>Foo</h1>
  <section>
    <p>One</p>
    <p>Two</p>
  </section>
  <Footer />
</div>

In this example the order of elements being visited would be:

div -> h1 -> "Foo" -> section -> p -> "One" -> p -> "Two" -> Footer

Whilst your application is being walked its behaviour will be much the same as if it were being rendered on the server - i.e. the componentWillMount lifecycle will be executed for any "class" components, and context provided by any components will be passed down and become available to child components.

Despite emulating a server side render, the tree walking process is far cheaper as it doesn't actually perform any rendering of the element tree to a string. It simply interogates your app building up an object/element tree. The really expensive cycles will likely be the API calls that you make. 😀

That being said you do have a bail-out ability allowing you to suspend the traversal down a branch of the tree. To do so you simply need to return false from your visitor function, or if returning a Promise ensure that the Promise resolves a false for the same behaviour.

API

The API is very simple at the moment, only exposing a single function. We will describe the API of the reactTreeWalker function below as well as the API for the visitor function that reactTreeWalker expects as a parameter.


reactTreeWalker

The default export of the library. The function that performs the magic.

const reactTreeWalker = require('react-tree-walker')

or

import reactTreeWalker from 'react-tree-walker'

Parameters

  • tree (React/Preact element, required)

    The react application you wish to walk.

    e.g. <div>Hello world</div>

  • visitor (Function, required)

    The function you wish to execute against each element that is walked on the tree.

    See its API docs below.

  • context (Object, optional)

    Any root context you wish to provide to your application.

    e.g. { myContextItem: 'foo' }

  • options (Object, optional)

    Additional options/configuration. It currently supports the following values:

    • componentWillUnmount: Enable this to have the componentWillUnmount lifecycle event be executed whilst walking your tree. Defaults to false. This was added as an experimental additional flag to help with applications where they have critical disposal logic being executed within the componentWillUnmount lifecycle event.

Returns

A Promise that resolves when the tree walking is completed.


visitor

The function that you create and provide to reactTreeWalker.

It should encapsulates the logic you wish to execute against each element.

Parameters

  • element (React/Preact element, required)

    The current element being walked.

  • instance (Component Instance, optional)

    If the current element being walked is a "class" Component then this will contain the instance of the Component - allowing you to interface with its methods etc.

  • context (Object, required)

    The React context that is available to the current element. react-tree-walker emulates React in exposing context down the tree.

  • childContext (Object, optional)

    If the current element being walked is a "class" Component and it exposes additional "child" context (via the getChildContext method) then this will contain the context that is being provided by the component instance.

Returns

If you return false then the children of the current element will not be visited.

e.g.

function visitor(element) {
  if (element.type === 'menu') {
    // We will not traverse the children for any <menu /> nodes
    return 'false'
  }
}

You can also return a Promise which will cause the tree walking to wait for the Promise to be resolved before attempting to visit the children for the current element.

function visitor(element, instance) {
  // This will make every visit take 1 second to execution.
  return new Promise(resolve => setTimeout(resolve, 1000))
}

You can make the Promise resolve a false to indicate that you do not want the children of the current element to be visited.

function visitor(element, instance) {
  // Only the first element will be executed, and it will take 1 second to complete.
  return (
    new Promise(resolve => setTimeout(resolve, 1000))
      // This prevents any walking down the current elements children
      .then(() => false)
  )
}

react-tree-walker's People

Contributors

bartlangelaan avatar birkir avatar ctrlplusb avatar eirikurn avatar ewolfe avatar grxy avatar mjadobson avatar sleepwalker 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  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

react-tree-walker's Issues

Promise resolved before the entire tree has been resolved

Context

I'm trying to use react-jobs and react-async-bootstrapper to replace a custom module (aqueduc).

Our application has some conditional rendering according to the data that have been fetched (example for a blog application: the component to fetch and render a comment is used in a component to render a blog post only rendering once the blog post has been fetched).

It looks like this use case is not supported by react-jobs.

Bug

But while I was testing, I've found an issue in react-tree-walker itself where the promise is resolved, but the "rendering" continues.

Here is an example file to reproduce the issue: https://gist.github.com/SamyPesse/4950194a9ca47c3d91e1226d93b3e802 (with the console output)

Behavior on server-side when using in conjunction with dynamic imports

Hi @ctrlplusb, while debugging ctrlplusb/react-jobs#51 & ctrlplusb/react-jobs#56, I realized that if there were jobs on dynamic import components, then those jobs wouldn't execute on the server-side since the components are not being imported before render is considered complete.

Here is a simple summarized hierarchy that could reproduced it for me -

<App>
  <Auth> /* <--- Fetch data */
    <Switch>
      <Route component = { AsyncProfile } />
      { /* AsyncProfile dynamically imports Profile which fetches the data */ }
    </Switch>
  </Auth>
<App>

Looking through codebases of this library and react-jobs, it seems like this issue should be resolved here. Thoughts on what should be the expected behavior?

Errror in Edge: 'Error walking react tree'

Hi,
after update to latest we started seeing

image

happens only in Edge.
I wish I could give more details but it is a pain to get anything from IE.
Fix would be appreciated though

Support Shallow Walk

It would be nice if you can optionally walk children only.

One way to do this is to have visitor function optionally return an array of elements to walk next. If it's type Array I think you can assume it is children and proceed with a breadth-first walk.

Example use case: https://github.com/amccloud/await-component

Issue with multiple children

I ran into the following problem where not all nested children would be visited:

This works

const A = ({ children }) => children
const B = ({ children }) => <div>{children}</div>

const tree = (
    <A>
        <B />
        <B />
    </A>
)

reactTreeWalker(tree, visitor, context)

So does this

const A = ({ children }) => <div>{children}</div>
const B = ({ children }) => children

const tree = (
    <A>
        <B />
        <B />
    </A>
)

reactTreeWalker(tree, visitor, context)

This does not work

Because there are no basic HTML elements wrapping the children of A, those individual children are not visited

const A = ({ children }) => children
const B = ({ children }) => children

const tree = (
    <A>
        <B />
        <B />
    </A>
)

reactTreeWalker(tree, visitor, context)

A PR will follow shortly and should provide a fix for this issue.

feature request: provide current element depth to visitor function

Hey @ctrlplusb, thanks for extracting this utility out for other libraries!

would you be inclined to pass the current element depth/index in the tree as the last argument to the visitor function? It's useful if you want to limit how far down you want to walk the component tree, e.g. if implementing a custom getInitialProps

Thanks

support for preact

Hi your library is working fine with react but I am using preact in production and from some reason you are not traversing all childrens of element. I can see that stateless function are not deeply traversed.

I am using next alias in webpack

    alias: {
      react: 'preact-compat/dist/preact-compat',
      'react-dom/server': 'preact-compat/server',
      'react-dom': 'preact-compat/dist/preact-compat',
    },

You should not use <Switch> outside a <Router>

Hi,i use react-async-bootstrapper on ssr,and it return
Error: Invariant failed: You should not use <Switch> outside a <Router> at invariant (E:\yx\react\todo\react-ssr\node_modules\[email protected]@tiny-invariant\dist\tiny-invariant.cjs.js:13:11) at Object.children (E:\yx\react\todo\react-ssr\node_modules\[email protected]@react-router\cjs\react-router.js:672:21) at recursive (E:\yx\react\todo\react-ssr\node_modules\[email protected]@react-tree-walker\dist\react-tree-walker.js:129:41) at E:\yx\react\todo\react-ssr\node_modules\[email protected]@react-tree-walker\dist\react-tree-walker.js:153:26 at process._tickCallback (internal/process/next_tick.js:68:7)
my code:

      <StaticRouter context={routerContext} location={url}>
        <App></App>
      </StaticRouter>
    </Provider>
const App = () => (
  <Switch>
    <Route exact path="/" component={Default} />
  </Switch>
)
return new Promise((resolve, reject) => {
    asyncBootstrapper(app).then(() => {
      if (routerContext.url) {
        res.status(302).setHeader('Location', routerContext.url)
        res.end();
        return;
      }
      const appString = ReactDomServer.renderToString(app); 
      const helmet = Helmet.rewind();
      let html = ejs.render(template, {
        meta: helmet.meta.toString(),
        link: helmet.link.toString(),
        style: helmet.style.toString(),
        title: helmet.title.toString(),
        appString,
        stylesString,
        scriptsString,
        initalState: serialize(getStoreState(storeMap)),
      });
      res.send(html);
      resolve();
    }).catch(reject)
  })

Support concurrent branch traversal

Likely through an experimental flag for now, but as long as we execute from root towards leaf in a concurrent fashion it should be fine as the parent context would have been configured for children.

issue with connect, outdated props when rendered

here is a repo to reproduce the issue but i will try to summarise it here
https://github.com/CosticaPuntaru/react-walk-tree--redux-bug

tl:dr;
in order for nested component to render properly the component instance needs to recalculate props after the "visitor" function is run and before render is called.

what i understand from what happens:
case: we have two components that want to lazy load data from server, one sibling of the other
(i call them first and second), both of them are decorated with redux connect

running steps:
reactWalkTree gets the App and walks it
runs the connector component, binds the store props to the component props,
then runs by "bootstrap" function,
waits for it to finish and then runs the render,

the issue is that the render function is called with the props that were bind to the component before the "bootstrap" function was called. and having a if(!ready) return (<div>Loading</div>); will never give a change to the secondComponent.bootstrap to run and gather the data. thus not not getting the correct ssr,

hope this is clear enough,

React tree walker can not walk children 2.0.0 react-async-component components

Hello!

We decided to bump "react-async-component": "1.0.2" to 2.0.0. We found that latest react-tree-walker now cannot walk children of the new AsyncComponents.

Versions in question:

    "react": "16.4.1",
    "react-async-bootstrapper": "1.1.2",
    "react-async-component": "2.0.0",
    "react-dom": "16.4.1",
    "react-helmet": "5.2.0",
    "react-hot-loader": "4.0.0",
    "react-router-dom": "4.2.2",
    "react-tree-walker": "4.3.0",

Fix new Context handling (react@^16.6.x)

As of react 16.6 the both Provider and Consumer types has _context property, which leads to context loss whenever we are visiting Consumer:

if (currentElement.type._context) {
  // eslint-disable-next-line no-param-reassign
  currentElement.type._context._currentValue =
    currentElement.props.value
}

The most naive way to fix it is to check whether we actually have value prop. There is more advanced approach here: jaydenseric/graphql-react@v3.0.0...v4.0.1#diff-3e6d5558503509cddfcf7ef1bc7ee575

Here is a demo of an error: https://codesandbox.io/s/o4wrj5m0jy

The example in the README results in all children being walked.

The example in the README has a few typos which stop it from working (getData vs. getValue), but I can fix those in a PR. The bigger issue is that running the code results in the output:

[1, 2, 4, 5, 3]

From experimenting, it seems like this library takes an approach similar to shallow rendering - all React elements present within a component's render method are traversed (even if nested within other components), but any components within that component's render method are not traversed.

This isn't very fun to describe in text, so two examples. In both cases, the walk is told to stop after hitting value="4", just like the current example:

const app = (
  <div>
    <h1>Hello World!</h1>
    <Foo value={1} />
    <Foo value={2}>
      <Foo value={4}>
        <Foo value={5} />
      </Foo>
    </Foo>
    <Foo value={3} />
  </div>
);

// result: [1,2,4,5,3]
const Container = ({ value }) => (
  <Foo value={value}>
    <Foo value={5} />
  </Foo>
);

const app = (
  <div>
    <h1>Hello World!</h1>
    <Foo value={1} />
    <Foo value={2}>
      <Container value={4} />
    </Foo>
    <Foo value={3} />
  </div>
);

// result: [1,2,4,3]

Is this accurate? If so, I can modify the example to match this.

Demo Question

In your demo you are walking "tree" but never create a "tree" - my guess is that should be "app" ?

ReactDOMServer.renderToString() recreates components tree from the scratch

Hello!
Thank you for this awesome lib, really solves a lot of problem with SSR.

However, there is a little but very annoying trick. Assume I have walked through my application components tree, collected and upfilled all necessary data. When resolving a promise, in place where you wrote Now is a good time to call React's renderToString in example, I'm calling it and... see that renderToString starts to recreate all my components tree from the scratch. And it's okay if my data is stored in external storages, but those data that is inside the state is obviously being lost, because renderToString starts to call constructors again.

Can you, please, give me an advice, how to deal with this weird behaviour? Because I suppose that creating an external storage for every small view is not so good idea.

Thank you in advance and sorry for "stackoverflowing" in issues.

Accept iterables and collections as children.

React supports rendering of iterables and collections as childrens. react-tree-walker does not support this at this moment leading to unexpected results when using Iterables (e.g. List from immutable-js) as children. Subtrees that are rendered in react are might be skipped by the visitor.

I created a minimal example that shows the issue: https://codesandbox.io/s/o9kzlrql86

Here are some links from the original react discussion:
Original Issue
Original PR

Would be great to have this feature!

BlueBird warning for problematic Promise usage

I am currently seeing this issue when replacing the native Promise with Bluebirds debug enhanced Promise:

Warning: a promise was created in a handler at react-tree-walker/commonjs/index.js:28:14 but was not returned from it, see http://goo.gl/rRqMUw

As I see the method is "inherited" from Sindres utilities.

I would be eager what you think on the issue or whether we want to fix it.

Type error in ssr development mode

In the development environment, using react ssr to report an error, the production environment is normal,

TypeError: Cannot read property 'dense' of undefined
    at Object.eval [as children] (webpack:///./node_modules/@material-ui/core/ListItem/MergeListContext.js?:27:31)
    at recursive (/Users/ender/learning/github/react-cnode/node_modules/react-tree-walker/dist/react-tree-walker.js:129:41)
    at /Users/ender/learning/github/react-cnode/node_modules/react-tree-walker/dist/react-tree-walker.js:153:26
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:189:7)

Could not handle instance-as-result from Stateless component

Original issue - gaearon/react-hot-loader#832
React-Hot-Loader is a bit hacky thing, and it's functional component wrapper will return an instance from render.
This is a not common, but absolutely legit behavior, called IndeterminateComponent. Used by Relay as I know (https://github.com/facebook/relay/blob/d77a34c6b5abddfe078b0d50c2d43181fe35d574/packages/react-relay/classic/container/RelayContainer.js#L1050-L1055, dont know anyone else).
Unfortunately react-tree-walker(React.Children.count, to be more correct) cannot stand this, throwing an error.

Example - https://codesandbox.io/s/6wz0or0rqk, or in original issue.

Rehydrate server -> client with unique IDs

I've implemented a basic HOC so components can load data on the server, and then rehydrate with that state in the client.

The issue I keep getting hung up on is how to track unique keys/ids for each component. As the walker traverses the tree, it should create a unique id for each component (exactly once) and then when the tree is traversed on the client side, it gets the same ids and can grab its props from a global state object.

All of my approaches seem to do alright until I start using the same component with different props, and then they just fall flat because the ids overwrite.

Here's some example code to help illustrate what i'm doing:

// HOC that will resolve a promise and pass the resolved promise
// as props of the wrapped component.

// react-tree-walker's visitor function will return the promise from `fetchProps` during traversal.
export default getProps => ComposedComponent => {
  let id = null

  class Component extends React.Component {
    state = {props: null}

    constructor (props, context) {
      super(props, context)
      const {store} = context

      // browser doesn't get an id since `fetchProps` already ran. Need to get id here.
      if (process.browser) {
        id = store.getNextId()
      }

      if (id) this.state = {props: store.get(id)}
    }

    fetchProps = async () => {
      const {store} = this.context
      const props = await fetch('...')
      if (!id) {
        id = store.getNextId()
      }

      store.register(id, props)
      this.setState({props})
      return true
    }

    render () {
      return <ComposedComponent {...this.state.props} />
    }
  }
}
const Component = ({page}) => <li>{page.title}</li>

export default asyncHoc(async ({props}) => {
  const page = fetch(`api/pages/${props.id}`)
  return {page}
})(Component)
const App = () => <div><Component id='1' /><Component id='2' /></div>

A promise was created in a handler at webpack-internal://...react-tree-walker... but was not returned

Warning: a promise was created in a handler at webpack-internal:///./node_modules/react-tree-walker/dist/react-tree-walker.js:30:14 but was not returned from it, see http://goo.gl/rRqMUw
      at new Promise (/Users/lgodda/src/clp-prototype/node_modules/bluebird/js/release/promise.js:79:10)

[clp-prototype 09:31]$ yarn list webpack react-tree-walker
yarn list v1.7.0
├─ [email protected]
└─ [email protected]

node -v
v8.9.4

Thanks!

Problems with context using react-jss

I'm using mui-org/material-ui (1.0.0-beta.28) and cssinjs/react-jss (8.3.3). When I run reactTreeWalker (4.0.2) against my application, I get an error from JSS that appears to be related to context. My application is able to be rendered without issue using ReactDOMServer.renderToString. I have used reactTreeWalker against this app in the past, but after we upgraded MUI/JSS we started seeing this problem.

react-jss code that might be relevant: https://github.com/cssinjs/react-jss/blob/v8.3.3/src/JssProvider.js#L24

The error:

TypeError: Cannot read property '6fc570d6bd61383819d0f9e7407c452d' of undefined
	at JssProvider.getChildContext (/Users/username/Projects/folder-name/project-name/node_modules/react-jss/lib/JssProvider.js:65:38)
	at /Users/username/Projects/folder-name/project-name/node_modules/react-tree-walker/commonjs/index.js:167:76
	at doTraverse (/Users/username/Projects/folder-name/project-name/node_modules/react-tree-walker/commonjs/index.js:79:68)
	at doVisit (/Users/username/Projects/folder-name/project-name/node_modules/react-tree-walker/commonjs/index.js:116:9)
	at /Users/username/Projects/folder-name/project-name/node_modules/react-tree-walker/commonjs/index.js:142:9
	at new Promise (<anonymous>)
	at reactTreeWalker (/Users/username/Projects/folder-name/project-name/node_modules/react-tree-walker/commonjs/index.js:70:10)
	at router.get (/Users/username/Projects/folder-name/project-name/server/client/server-side-rendering.js:76:2)
	at Layer.handle [as handle_request] (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/layer.js:95:5)
	at next (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/route.js:137:13)
	at Route.dispatch (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/route.js:112:3)
	at Layer.handle [as handle_request] (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/layer.js:95:5)
	at /Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:281:22
	at param (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:354:14)
	at param (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:365:14)
	at Function.process_params (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:410:3)
	at next (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:275:10)
	at Function.handle (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:174:3)
	at router (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:47:12)
	at Layer.handle [as handle_request] (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/layer.js:95:5)
	at trim_prefix (/Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:317:13)
	at /Users/username/Projects/folder-name/project-name/node_modules/express/lib/router/index.js:284:7

Thanks in advance for any help or guidance you can offer.

Add a note that this is discouraged

Hi! I help maintain React.

I realize where the need is coming from, but I would appreciate if the project included a large disclaimer that this approach is discouraged. It is very fragile, already doesn’t match the exact semantics of React, and the gap will only widen in the future. We don’t recommend any libraries that want to work well with React in longer term to depend on this, or to use an approach like this.

What’s the alternatives? We are currently working on getting Suspense ready for use in open source. That should eventually cover data fetching needs (which is what motivated Apollo to do this). For other needs there may be other appropriate solutions.

Sorry to be a bummer. Thanks!

Error walking you react tree

For some reason I´m getting the "Error walking your react tree" message as follows:

Error walking your react tree

Error walking your react tree
{ Invariant Violation: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.
    at invariant (D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\invariant\invariant.js:42:15)
    at invariantIntlContext (D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\react-intl\lib\index.js:356:5)
    at new FormattedMessage (D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\react-intl\lib\index.js:1406:9)
    at D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\react-tree-walker\commonjs\index.js:132:24
    at reactTreeWalker (D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\react-tree-walker\commonjs\index.js:71:10)
    at mapper (D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\react-tree-walker\commonjs\index.js:89:29)
    at D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\react-tree-walker\commonjs\index.js:53:28
    at D:\9. DEV\WORKSPACE\mz-boilerplate-intl\node_modules\react-tree-walker\commonjs\index.js:39:14 name: 'Invariant Violation', framesToPop: 1 }
==> SERVER -> Error in server execution, check the console for more info.
(node:11228) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Invariant Violation: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.


I´m using server side rendering with react-intl, that calls the react-tree-walker package. My code:

`/* eslint-disable global-require */

import React from 'react';
import { render } from 'react-dom';
import { AsyncComponentProvider } from 'react-async-component';
import { AppContainer } from 'react-hot-loader';

import { IntlProvider, addLocaleData } from 'react-intl';
import en from 'react-intl/locale-data/en';
import pt from 'react-intl/locale-data/pt';
import es from 'react-intl/locale-data/es';

import './polyfills';

import ReactHotLoader from './components/ReactHotLoader';
import DemoApp from '../shared/components/DemoApp';

import localeData from '../../intl/messages.json';

const container = document.querySelector('#app');

addLocaleData([...en,...pt,...es]);

const language = (navigator.languages && navigator.languages[0]) ||
                  navigator.language ||
                  navigator.userLanguage;

const languageWithoutRegionCode = language.toLowerCase().split(/[_-]+/)[0];

const messages = localeData[languageWithoutRegionCode] || localeData[language] || localeData.en;

function renderApp(TheApp) {
  const app = (
      <IntlProvider locale={language} messages={messages}>
            <TheApp />
      </IntlProvider>
  );

  asyncBootstrapper(app).then(() => render(app, container));
}

renderApp(DemoApp);

if (process.env.BUILD_FLAG_IS_DEV === 'true' && module.hot) {
  module.hot.accept('./index.js');
  module.hot.accept('../shared/components/DemoApp', () => {
    renderApp(require('../shared/components/DemoApp').default);
  });
}

MyDemo component:

import 'normalize.css/normalize.css';

import React from 'react';

import { FormattedMessage } from 'react-intl';

function DemoApp() {
  return (
    <div>
      <h1>This is a test</h1>
      <FormattedMessage id={'Header.Title'} defaultText={'This is a header test title'} />
    </div>
  );
}

export default DemoApp;

Any ideas why the tree is not finding the IntlProvider component ? Thanks for helping.

React.forwardRef is not supported

I love that you made the new 16.3 context features work with this module.

The new React.forwardRef function however doesn't seem to work yet. I have made a code sample here: https://codesandbox.io/s/n4r8zwxz0l.

When the SubComponent in the example is directly rendered it works, but when wrapped with the React.forwardRef function it doesn't.

Trying to run this with MobX returns error.

reactTreeWalker(
  <Provider store={store}>
    <Router location={req.url} context={context}>
      <App userAgent={userAgent} />
    </Router>
  </Provider>, () => { 
    return true;
  }
)

returns this error;

Error walking your react tree
TypeError: Cannot read property 'mobxStores' of undefined

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.