- Notifications
You must be signed in to change notification settings - Fork34
Walk a React (or Preact) element tree, executing a "visitor" function against each element.
License
ctrlplusb/react-tree-walker
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
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 recommendreact-ssr-prepass, developed by @kitten of Formidable Labs, which provides the same functionality with built in support for suspense.
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.
Walk a React (or Preact) element tree, executing a "visitor" function against each element.
Inspired/lifted from the awesomereact-apollo project. 😗
This modified version expands upon the design, making itPromise based, allowing the visitor to return aPromise, which would subsequently delay the tree walking until thePromise 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.
In the below example we will create a visitor that will walk a React application, looking for any "class" component that has agetData method on it. We will then execute thegetData function, storing the results into an array.
importreactTreeWalkerfrom'react-tree-walker'classDataFetcherextendsReact.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.returnPromise.resolve(this.props.id)}render(){return<div>{this.props.children}</div>}}constapp=(<div><h1>Hello World!</h1><DataFetcherid={1}/><DataFetcherid={2}><DataFetcherid={3}><DataFetcherid={4}/></DataFetcher></DataFetcher><DataFetcherid={5}/></div>)constvalues=[]// You provide this! See the API docs below for full details.functionvisitor(element,instance){if(instance&&typeofinstance.getData){returninstance.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.returnvalue!==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 aredux state, subsequently performing arenderToString execution with all the required data in place.
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" -> FooterWhilst your application is being walked its behaviour will be much the same as if it were being rendered on the server - i.e. thecomponentWillMount 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 returnfalse from your visitor function, or if returning aPromise ensure that thePromise resolves afalse for the same behaviour.
The API is very simple at the moment, only exposing a single function. We will describe the API of thereactTreeWalker function below as well as the API for thevisitor function thatreactTreeWalker expects as a parameter.
The default export of the library. The function that performs the magic.
constreactTreeWalker=require('react-tree-walker')
or
importreactTreeWalkerfrom'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 againsteach element that is walked on the
tree.See itsAPI 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
componentWillUnmountlifecycle event be executed whilst walking your tree. Defaults tofalse. This was added as an experimental additional flag to help with applications where they have critical disposal logic being executed within thecomponentWillUnmountlifecycle event.
- componentWillUnmount: Enable this to have the
Returns
APromise that resolves when the tree walking is completed.
The function that you create and provide toreactTreeWalker.
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-walkeremulates 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
getChildContextmethod) then this will contain the context that is being provided by the component instance.
Returns
If you returnfalse then the children of the current element will not be visited.
e.g.
functionvisitor(element){if(element.type==='menu'){// We will not traverse the children for any <menu /> nodesreturn'false'}}
You can also return aPromise which will cause the tree walking to wait for thePromise to be resolved before attempting to visit the children for the current element.
functionvisitor(element,instance){// This will make every visit take 1 second to execution.returnnewPromise(resolve=>setTimeout(resolve,1000))}
You can make the Promise resolve afalse to indicate that you do not want the children of the current element to be visited.
functionvisitor(element,instance){// Only the first element will be executed, and it will take 1 second to complete.return(newPromise(resolve=>setTimeout(resolve,1000))// This prevents any walking down the current elements children.then(()=>false))}
About
Walk a React (or Preact) element tree, executing a "visitor" function against each element.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors10
Uh oh!
There was an error while loading.Please reload this page.