Best pattern to rerender my react component? - javascript

I have a global data object I update and then I call React.renderComponent() again on the top/main component.
Is this the right pattern for triggering this update?

You should generally pass the data object into the component as a prop, even if it's a global variable. This lets you test the component, and also use it elsewhere without being tied to that global.
As Mike said, there's nothing wrong with using React.renderComponent to update it.
He also mentioned flux, but that's overkill for this. A simple event emitter where you do something like .emit('change', newData), and the component is listening for the change event tends to be better for simpler cases. See my answer to this question for an example of how that can be done.

This is the correct pattern. React.renderComponent will either mount a component for the first time, or get an already mounted component to update.
If you're using a global object though, you might want to look in to the Flux architecture here:
http://facebook.github.io/flux/docs/overview.html

I had the same problem and asked myself if I really needed to re-render the component.
You can do so with this.forceUpdate() but it's not advisable. As React docs states:
You should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render(). This makes your component "pure" and your application much simpler and more efficient.
So what I did was create a data property like exists and test it:
// renderDeleteButton() is being called on render()
renderDeleteButton () {
if (!this.props.store.exists) {
return;
}
return(
<DeleteButton
...
deleteAction={this.delete} />
);
}
Whenever I delete/save, I toggle exists and component will show up or hide based on that. React handles that for me.

Related

Is it good practice to pass component instance as props to another component in VueJs?

Assume that we are going to make a text edior.
When typing, Component C(Text input section) needs the state of Component B(Font stlye picker) to determine what style to use.
We can share that state by Vuex, but in OOP, related logic or variables are better to be put in same class, and when other components need the state of that object, just to refer it directly.
If I want to refer components directly, one way is to save some components when they are mounted, and pass them as props to other components as the following.
// in <template>
<FontStylePickerVue ref="stylePicker" />
<TextInputSectionVue
ref="textInputSection"
v-bind="{
tylePickerComp: stylePickerComp
}" />
//in Main Component <script>
mounted(){
this.tylePickerComp = this.$refs.stylePicker;
}
data(){
return { tylePickerComp : null }
}
In Vue, although there are many ways to communicate between components, I never seen any of them passes component instance as props directly like this.
(it works, and very convinient though.)
I know doing like this, in a way, it make system more complicated because components refer each others in a complex relation, but I'm just wondering if there is any design pattern like this in Vue, or doing like this has some cons like low perfermance ,etc.
In the end, in order to clarify the idea, I want to compare what if I pass component as props directly or use common methods in this example:
Pass component as props directly:
Need to save component reference on mounted, but type declartion is once and for all(ex. use InstanceType). Need to deal with null(it's null before mounted).
Event bus:
Emit an event with a promise resolve function as callback to make other components to resovle with their state. This is good because it will keep data or logic in the same class(compare to use Vuex), but you need to write your method in a promise style in order to read resolved result.
Vuex:
Split some variables into global scope, and this is not so compatible for cases which are better to gather logic and data at same place.
Just want to get some idea for this topic, sorry for long article.

Is it good practice to set CSS variable in the React's render method?

I have created a post yestarday and deleted it by error
I have to create a component with specific style. The problem is that the componentDidMount() method creates some king of flickering when rendering the component. It is the time that the CSS became set.
I think my component is ressource's demanding so the componentDidMount() occurs with a little frame or two of lagging. That why I am providing here just a snippet instead of a full demo, my little demo works well with zero specific flickering.
I have then entering the value in the render's method. Like the following:
componentDidMount(){
// the CSS rendering will lag by releasing a flickering :/
}
render(){
// awesome, by setting my style in the render the good style is returned instantly.
if (Math.round(window.scrollY + window.innerHeight +50) >= Math.round(document.body.scrollHeight)) {
document.documentElement.style.setProperty('--background-transition', "")
document.documentElement.style.setProperty('--is-page-bottom', "orange");
document.documentElement.style.setProperty('--background-transition', "all 0.3s ease-out")
}
else{
//setIsPageBottom_CSSVariable("rgba(84, 80, 79,0.85)")
document.documentElement.style.setProperty('--background-transition', "")
document.documentElement.style.setProperty('--is-page-bottom', "purple");
document.documentElement.style.setProperty('--background-transition', "all 0.3s ease-out")
}
Someone yesterday told me that I should use react React Hook to manage this case, or componentDidMount but componentDidMount fails in my case because of the flickering before installing the relevant background color.
I am new to React Hook so if I understand well I can make something like document.documentElement.style.setProperty in useEffect directly and it would be coherent with the design of React hook?
Meanwhile I find my solution is just good because when reading the official React's documentation, it is noted that:
The render() function should be pure, meaning that it does not modify
component state, it returns the same result each time it’s invoked,
and it does not directly interact with the browser.
If you need to interact with the browser, perform your work in
componentDidMount() or the other lifecycle methods instead. Keeping
render() pure makes components easier to think about.
Okay, if I can think about my component with a limpid manner so it is in no way a bad thing to do it isn't it? Just not the best practice I assume.
I have been advised to use an addeventlistener but here it is about instantly rendering my style on the first render component's loop. So addeventlistener is a solution for a different case that the one I am on.
In all case, which alternative would you recommend that avoid flickering when inserting my CSS setting in componentDidMount()? What is the link with the React hook?
This is how you can use useEffect
//componentDidMount replacement
useEffect(() => {
//your code goes here
}, [])
You might also consider useLayoutEffect as it fires synchronously with the DOM changes. If normal useEffect retains the issue, then you should be able to use this instead.
No, it's not good practice - you would be better off changing the class name dynamically using react, dependent on the internal state of the component.
So you could use the useState hook, and have your component in a 'loading state' which would then apply a class.
Then you could add / remove class names and associated styles using react as well, rather than inserting them with JS.
Have a look at the classNames package: https://www.npmjs.com/package/classnames
Your css would then be: .additional-class {
background: red;
}
or whatever you wanted.
Applying styles directly from React is somewhat missing the point of using react, to be honest. If you do want to do that, there are ways but should be limited, really: How to modify the DOM directly in ReactJS
https://reactjs.org/docs/refs-and-the-dom.html

React Hooks - What's happening under the hood?

I've been trying out React Hooks and they do seem to simplify things like storing state. However, they seem to do a lot of things by magic and I can't find a good article about how they actually work.
The first thing that seems to be magic is how calling a function like useState() causes a re-render of your functional component each time you call the setXXX method it returns?
How does something like useEffect() fake a componentDidMount when functional components don't even have the ability to run code on Mount/Unmount?
How does useContext() actually get access to the context and how does it even know which component is calling it?
And that doesn't even begin to cover all of the 3rd party hooks that are already springing up like useDataLoader which allows you to use the following...
const { data, error, loading, retry } = useDataLoader(getData, id)
How do data, error, loading and retry re-render your component when they change?
Sorry, lots of questions but I guess most of them can be summed up in one question, which is:
How does the function behind the hook actually get access to the functional/stateless component that is calling it so that it can remember things between re-renders and initiate a re-render with new data?
React hook makes use of hidden state of a component, it's stored inside a fiber, a fiber is an entity that corresponds to component instance (in a broader sense, because functional components don't create instances as class components).
It's React renderer that gives a hook the access to respective context, state, etc. and incidentally, it's React renderer that calls component function. So it can associate component instance with hook functions that are called inside of component function.
This snippet explains how it works:
let currentlyRenderedCompInstance;
const compStates = new Map(); // maps component instances to their states
const compInstances = new Map(); // maps component functions to instances
function useState(initialState) {
if (!compStates.has(currentlyRenderedCompInstance))
compStates.set(currentlyRenderedCompInstance, initialState);
return [
compStates.get(currentlyRenderedCompInstance) // state
val => compStates.set(currentlyRenderedCompInstance, val) // state setter
];
}
function render(comp, props) {
const compInstanceToken = Symbol('Renderer token for ' + comp.name);
if (!compInstances.has(comp))
compInstances.set(comp, new Set());
compInstances.get(comp).add(compInstanceToken);
currentlyRenderedCompInstance = compInstanceToken;
return {
instance: compInstanceToken,
children: comp(props)
};
}
Similarly to how useState can access currently rendered component instance token through currentlyRenderedCompInstance, other built-in hooks can do this as well and maintain state for this component instance.
Dan Abramov created a blog post just a couple days ago that covers this:
https://overreacted.io/how-does-setstate-know-what-to-do/
The second half specifically goes into details regarding hooks like useState.
For those interested in a deep dive into some of the implementation details, I have a related answer here: How do react hooks determine the component that they are for?
I would recommend reading https://eliav2.github.io/how-react-hooks-work/
It includes detailed explanations about what is going on when using react hooks and demonstrate it with many interactive examples.
Note - the article does not explain in technical terms how React schedule calls for later phases, but rather demonstrates what are the rules that react uses to schedule calls for later phases.
The URL in another answer given by Eliav Louski is so far the best React explaination I have come across. This page should replace React's official tutorial as it removes all the magic from hooks and friends.

Can this state management be done on the react?

the code is here
I want to know that is right? thanks!
Firstly, Please post your code in the question and describe clearly
With getLabels function, you should bind(this) in constructor or use arrow function then you can this.setState in getLabels function.
ex:
constructor(props){
super(props)
this.getLabels = this.getLabels.bind(this)
}
Or:
getLabels = () => {}
You can manage state with react if your application is small, refer here to know how to maintain state in react.
when your applications grows big its difficult to track the state, you may have to go for redux, refer here to know more about redux.
First thing first. "getLabels" functions name is wrong. "setLabels" would be a better name since what you do is assigning the labels to state after retrieving them. So if the rest of the code written correctly it'll trigger a re-render in the component and the UI will be updated with the new state.
if this gets called from a UI button or something, then you'll have to bind to this.
<input type="button" onClick={this.getLabels.bind(this)}/>
Else if it get's called from another function in the same component you can just call it.
function abc(){
this.getLabels()
}
Other than that this is ok for a basic app. But it's better you use some state management pattern like Redux to manage the code and the state.

Utilizing componentDidMount when switching between different instances of the same React component

According to the react documentation: http://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount we are adviced use componentDidMount for AJAX call that should be issued when a component is brought into view.
However, when switching between to instances of the same component with different props, componentDidMount is only called for the first component. So what are we supposed to do in this situation?
Currently I have the following workaround: In componentDidMount i do my AJAX call and In componentDidUpdate I compare old and new props to check if I am on a new "instance", and if so I do my AJAX call. But that seems exactly like a workaround. So my question is: is this really the way to do it?
I am aware that I could wrap my component in different empty components to solve my problem. However, this is not possible because we are building a data driven application that uses configurable components and it makes sense to use the same component with different configurations - which is where I'm running into problems.
I am aware that we are actually talking about react elements and not instances as such - witch I guess is part of the problem. Probably I have different react elements utilizing the same instance.
I have made a tiny example to illustrate the react behavior, using plain react (just to make sure I wasn't tricked by react-router or redux and what else we are using the real app):
class Foo extends React.Component {
componentDidMount() {
console.log('componentDidMount ' + this.props.foo);
}
componentDidUpdate() {
console.log('componentDidUpdate ' + this.props.foo);
}
render() {
return <div>Route is {this.props.foo}</div>;
}
}
function navigated() {
ReactDOM.render(
<Foo foo={window.location.hash} />,
document.getElementById('app')
);
}
window.addEventListener('hashchange', navigated, false);
navigated();
Initially when I go to #/bar I get 'componentDidMount #/bar' and when I go to #/baz i get 'componentDidUpdate #/baz'.
I seems like this unanswered question is a specific case of the same issue: React does not know when i render the same component
You can add the key property with unique value for each of hashes:
ReactDOM.render(
<Component hash={hash} key={hash} />, domNode
);
This will update the component every time when the hash is really changed.
https://facebook.github.io/react/docs/multiple-components.html#dynamic-children
TL DR - your 'workaround' looks correct to me
When you initially render the component componentDidMount is called, when you change the hash prop componentDidUpdate is called. It is still the same component, it is just that a specific prop has changed value. In your case, you have logic (running an AJAX call when hash changes) that is specific to your application. React does not known that the hash prop is special, you make is special by adding the logic in componentDidMount. So I believe you have a good interpretation of the React docs and this way of achieving your goal is perfectly valid.

Categories

Resources