📜 ⬆️ ⬇️

Review of the React quiz competition from the HeadHunter booth at HolyJs 2018

Hey. September 24–25, HolyJs frontend developers conference https://holyjs-moscow.ru/ took place in Moscow. We came to the conference with our booth where we spent quiz. There was the main quiz - 4 qualifying rounds and 1 final, in which Apple Watch and Lego designers were raffled. And separately, we held a quiz on knowledge.


Under the cut - analysis of tasks quiz on react. The correct options will be hidden under the spoiler, so you can not only read the analysis, but also check yourself :)


image


Go!


For convenience, we have grouped the questions into sections:


Section 1. Basic understanding of how this.setState works and when updating the component lifecycle:


Question 1.


      react-: 1) SetProps, SetState, ForceUpdate 2) ForceUpdate, SetState 3) ForceUpdate, SetState, Parent (re)render 4) ForceUpdate, SetState, directly call UpdateComponent 

Answer

3) ForceUpdate, SetState, Parent (re) render


Question 2.


  ,   this.setState({})  react 1)   ,  updating lifecycle 2)   ,    3) React    "Object cannot be empty" 4)    state   

Answer

1) The component is marked dirty, updating lifecycle will be called


Parsing questions 1 and 2

To answer the question we will analyze 2 parts:
1) Own component request for updating cycle
2) Query outside the component


The component itself has 2 ways to update itself:
1) this.setState and this.forceUpdate. In this case, the component will be marked dirty and on the Reconcilliation tick, if it is in priority for rendering, the updating cycle will start.


Interesting fact: this.setState({}) and this.forceUpdate are different. When this.setState({}) is called, the full updating cycle is called, unlike this.forceUpdate , when the updating cycle starts without the shouldComponentUpdate method. An example of how this.setState({}) works can be found here: https://codesandbox.io/s/m5jz2701l9 (if you replace forceS in the example setState with forceUpdate, you can see how the behavior of the components will change).


2) When the parent of the component is rendered, it returns the part of the vDOM, all the children that will have to be updated - and they will also have a full updating lifecycle. A full translation of the subtree can be avoided by describing shouldComponentUpdate or by defining the component as PureComponent.


Question 3


   Component  PureComponent (PC) 1) Component   ,    Pure 2) PC  SCU,  shallowEqual props  state 3) PC    ,    store 4)  PC    shouldComponentUpdate 

Answer and analysis

2) PC implements SCU, conducts shallowEqual props and state


As we discussed earlier, when (re) rendering the parent, the entire subtree will be sent to the updating lifeCycle. Imagine that you have updated the root element. In this case, the chain effect you should be updated almost the entire react-tree. In order to optimize and not send too much updating, there is a method shouldComponentUpdate , which allows to return true if the component should be updated, and false otherwise. To simplify the comparison in react, you can inherit from PureComponent to get immediately ready shouldComponentUpdate , which compares by reference (if we are talking about object types) or by value (if we are talking about value types) all props and state that come into the component.


Question 4.


 this.setState(() => {}, () => {}) —       setState? 1) set   .    updating 2)       state 3) setState   1  

Answer and analysis

2) The second function will be called after the state is updated.


There are two methods in React-lifecycle: componentDidMount for the mounting loop and componentDidUpdate for updating, where you can add some logic after updating the component. For example, make an http request, make some style changes, get the metrics of html elements and (by condition) make setState. If you want to do some kind of action after changing certain fields in the state, then in the componentDidUpdate method you will have to write or compare:


 componentDidUpdate(prevProp, prevState) { if (prevState.foo !== this.state.foo) { // do awesome things here } } 

Or you can do this by setState:


 setState( // set new foo {foo: 'baz'}, () => { // do awesome things here } ); 

Each approach has pros and cons (for example, if you change setState in several places, it may be more convenient to write a condition once).


Question 5.


       render: class A extends React.PureComponent { render() { console.log('render'); return <div /> } } function Test() { return <A foo='bar' onClick={() => console.log('foo')} /> } const rootElement = document.getElementById("root"); ReactDOM.render(<Test />, rootElement); setTimeout(() => ReactDOM.render(<Test />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

Answer

2) 2


Question 6.


       render: class A extends React.PureComponent { render() { console.log('render'); return <div /> } } function Test() { return <A foo='bar' /> } const rootElement = document.getElementById("root"); ReactDOM.render(<Test />, rootElement); setTimeout(() => ReactDOM.render(<Test />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

Answer

eleven


Question 7.


       render: class A extends React.PureComponent { componentDidMount() { console.log('render'); } render() { return <div /> } } const rootElement = document.getElementById("root"); ReactDOM.render(<A />, rootElement); setTimeout(() => ReactDOM.render(<A />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

Answer

eleven


Analysis questions 5-7

Questions 5–7 Needed for the same thing - to check the understanding of the operation of PureComponent and component updates during the transfer of props. If inside the render method we pass in the form of a jsx callback, describing it directly in the render function:


 render () { return <Button onClick={() => {}} />; } 

Then each render parent will update this click handler. This happens because with each render a new function is created with a unique link, which, when compared in PureComponent, will show that the new props are not equal to the old ones and the component needs to be updated. In the case when all checks pass and shouldComponentUpdate returns false, the update does not occur.


Section 2. Keys in React


A detailed analysis of the work of the keys we published here: https://habr.com/company/hh/blog/352150/


Question 1.


     key,      ? 1)         key 2)    updating lifecycle 3)   key  4)    reconciliation 

Answer and analysis

1) Delete the previous instance and make a new one when changing the key


Without using key reacts, it will compare the list of elements in pairs from top to bottom. If we use key, the comparison will occur on the corresponding key. If a new key appears, then such a component will not be compared with anyone and it will immediately be created from scratch.
This method can be used even if we have 1 element: we can set <A key="1" /> , in the next render we specify <A key="2" /> and in this case, react will delete <A key="1" /> and create from scratch <A key="2" /> .


Question 2.


       this.prop.key? 1)  2)  3)   static getKey 

Answer and analysis

2) No


A component can learn the key from its children, which were given to it as a prop, but cannot find out about its key.


Question 3.


       render: class A extends React.PureComponent { componentDidMount() { console.log('render'); } render() { return <div /> } } const rootElement = document.getElementById("root"); ReactDOM.render(<A key='1' />, rootElement); setTimeout(() => ReactDOM.render(<A />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

Answer and analysis

2) 2


When the key is changed, the component will be recreated, so the render will be displayed twice.


Section 3. Questions on jsx


Question 1.


   .           1)    prop / context 2)        3)  setParentProps 4)  static getParentRef 

Answer and analysis

1) Callback in the form of prop / context
2) Take out the model layer and work through it


There are two correct answers here. The choice of any of them on the quiz will count you points. This question is for knowledge of data-flow react. Data from top to bottom is distributed in the form of props or context, there may be a callback, which the component below can call to affect the state of the system.
Another way of combining the model take-off, context and prop, is, for example, react-redux binding.
This library takes the model derived from the react (redux). Setit redux.store in Provider, which actually sets store in context. The developer then uses HOC connect, which goes into context, subscribes to the store (store.subscribe) changes, and when the store changes, it recalculates the mapStateToProps function. If the data has changed, set it to props in the object being wrapped.
At the same time, connect allows you to specify mapDispatchToProps , where the developer specifies the actionCreators to be transferred to the component. We, in turn, receive them from the outside (without context), bind the actionCreators on the store (we wrap them in store.dispatch) and pass props to the wrapped component as props.


Question 2.


   props   jsx?     1)   2)   children 

Answer and analysis

1) In any


You can transfer to any. For example:


 <Button icon={<Icon kind='warning'/>}></Button> 

Draws a button with an icon. This approach is very convenient to use to leave the component the right to control the location of the various elements relative to each other, and not to touch one children prop.


Section 4. Advanced understanding of setState


Here are 3 strongly related questions:


Question 1.


 this.state = {a: 'a'}; ... this.setState({a: 'b'}); this.setState({a: this.state.a + 1}) this.state? 1) {a: 'a1'} 2) {a: 'b1'} 3)   4) {a: 'a'} 

Answer

3) Not enough data


Question 2.


 this.state={a: 'a'} ... this.setState({a: 'b'}) this.setState(state => ({a: state.a + 1})) this.state? 1) {a: 'a1'} 2) {a: 'b1'} 3)   4) {a: 'ab1'} 

Answer

2) {a: 'b1'}


Question 3.


    2 setState  componentDidUpdate  updating lifecycle   1) 1 2) 2 3) 3 4)   

Answer

eleven


Debriefing 1-3

All setState work is fully described here:
1) https://reactjs.org/docs/react-component.html#setstate
2) https://stackoverflow.com/questions/48563650/does-react-keep-the-order-for-state-updates/48610973#48610973


The fact is that setState does not occur synchronously.
And if there are several calls to setState in a row, then depending on whether we are inside the react-lifecycle method, the react-event handler function (onChange, onClick) or not, the execution of setState depends.
Inside the react handlers, setState runs batch (changes are rolled only after the user functions in the call stack have run out and we’ll fall into the functions that our event handler and lifecycle methods called). They roll in a row one after another, so in case we are inside a react-handler, we get:


 this.state = {a: 'a'}; // a: 'a' ... this.state.a // a: 'a' this.setState({a: 'b'}); // a: 'b' +   .       this.state.a // a: 'a' this.setState({a: this.state.a + 1}) // a: 'a1' 

since the changes occurred batchevo.
But at the same time, if setState was called outside of the react-handlers:


 this.state = {a: 'a'}; // a: 'a' ... this.state.a // a: 'a' this.setState({a: 'b'}); // a: 'b' +     this.state.a // a: 'b' this.setState({a: this.state.a + 1}) // a: 'b1' +     

As in this case, the changes will roll separately.


Section 5. Redux


Question 1.


     action,  () => {} ? 1) .  action      type 2) ,   action      type 3) ,    middleware   action 4) ,       dispatch 

Answer and analysis

3) Yes, you need to define custom middleware for such an action


Take redux-thunk as the simplest example. All middleware is a small block of code:
https://github.com/reduxjs/redux-thunk/blob/master/src/index.js#L2-L9


 return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; 

How do middleware work?
They get control before action comes to the store. Therefore, the action, which was zadispachen, first pass through a chain of middleware.
Each middleware accepts an instans store, the next method, which allows forwarding the action further, and the action itself.
If the middleware handles custom action, such as redux-thunk, for example, if it is an action, it does not forward the action, but “drowns out” it, instead calling the action and passing the dispatch method and getState to it.
What would happen if redux-thunk did next for action, which is a function?
Before calling the store, the store checks the action type. It must satisfy the following conditions:
1) It must be an object.
2) It should have a type field
3) The type field must be of type string


If one of the conditions is not met, redux will generate an error.


Bonus questions:


Bonus Question 1.


   ? class Todos extends React.Component { getSnapshotBeforeUpdate(prevProps, prevState) { return this.props.list.length - prevProps.list.length; } componentDidUpdate(a, b, c) { console.log(c); } ... } ReactDOM.render(<Todos list={['a','b']} />, app); setTimeout(() => ReactDOM.render(<Todos list={['a','b','a','b']} />, app), 0); a) 0 b) 1 c) 2 d) undefined 

Answer and analysis

c) 2


getSnapshotBeforeUpdate is a rarely used function in react that allows you to get snapshots, which will then be passed to componentDidUpdate. This method is needed to calculate in advance certain data, on the basis of which you can then make, for example, a fetch query.


Bonus Question 2.


        2,5 ? function Input() { const [text, setText] = useState("World!"); useEffect( () => { let id = setTimeout(() => { setText("Hello " + text); }, 1000); return () => { clearTimeout(id); }; }, [text] ); return ( <input value={text} onChange={e => { setText(e.target.value); }} /> ); } a) "World!" b) "Hello World!" c) "Hello Hello World!" d)    

Answer

c) "Hello Hello World!"


This is a question about the knowledge of new features in the react, it was not in our quiz. Let's try in the comments to describe in detail the work of the code from the last question :)


')

Source: https://habr.com/ru/post/431492/


All Articles