React - Stete & Props & Data Flow & Currying

Last Updated on: November 21, 2021 am

React State & Props

  • State是Component对内的接口。
  • Props是Component对外的接口。

Main Difference

  • State is mutable. It’s a list of states showing the change of UI Component.
  • Props is Read only. A component never modify its props.

Difference between Props and State

Props

State

如何判断一个变量是否应该作为State?

  • Got from Parent Component.
  • Immutable in the whole lifecycle.
  • Cannot be computed from other state/props.
  • Should be used in the render() function.

setState’s Asynchronous Nature

The setState method is an Asynchronous method and that’s batched. Multiple setState calls are batched before a component is rendered with a new state.

The setState method takes up to 2 arguments and it is a call back function. (Although we usually only pass one argument)

  • The first argument can be an object or a callback that is used to update the state.
  • The second argument is a function that always runs after the setState is run. (Hooks nature)

Example

We want a button which increments the counter by 3 when clicked.

Wrong:

1
2
3
4
5
6
handleClick = () => {
const { counter } = this.state;
this.setState( { counter: counter + 1 } );
this.setState( { counter: counter + 1 } );
this.setState( { counter: counter + 1 } );
}

In this way the counter will only increment by 1 when clicked. Because react will batch the objects in setState into one, which means that the objects passed into setState were shallow merged.

Correct:

  • Method 1
1
2
3
4
5
handleClick = () => {
this.setState( prev => ( { counter: prev.counter + 1 } ) );
this.setState( prev => ( { counter: prev.counter + 1 } ) );
this.setState( prev => ( { counter: prev.counter + 1 } ) );
}
  • Method 2
1
2
3
4
5
6
7
8
9
10
11
12
handleClick() => {
this.setState(
({ count }) => ({
count: count + 1
}), // the first argument (function)
() => {
this.setState(({ count }) => ({
count: count + 2
}));
} // the second argument (callback function)
);
}

Unidirectional Data Flow

In react, the unidirectional data flow means:

  • State is passed to view and to child components
  • Actions are triggered by the view

Passing from Parent to Child

Using Props to pass parent component’s State to child component.

在引用子组件的时候传值。相当于将一个属性传入子组件。例如:在子组件内通过props.param获取这个param的值。

Parent Component

Parent component has a state param: message

1
2
3
4
5
6
7
8
9
10
11
12
constructor(props){
super(props)
this.state={
message:"i am from parent"
}
}
render(){
return(
<Child txt={this.state.message}/>
)
}
}

Child Component

子组件从父组件的state中取出该值text

1
2
3
4
5
6
const { text } = this.props;
render(){
return (
<p> { text } </p>
)
}

Note: The name of the para in parent component is message (in State), while the name this para in child component is text which is used to pass from parent when calling the child component.

Passing from Child to Parent

子组件通过调用父组件传到子组件的方法向父组件传值。

  1. Create a callback function in parent component which is used to get data from the child component.
  2. Pass the callback function in the parent as a props to the child component.
  3. The child component will call the parent callback function using props.

Parent Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import React from "react";
import Child from "./Child";

class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null,
};
}

handleCallback = (childData) => {
this.setState({ data: childData });
};

render() {
const { data } = this.state;
return (
<div>
<Child parentCallback={this.handleCallback} />
<div>{data}</div>
</div>
);
}
}

export default Parent;

Child Component

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React from "react";

class Child extends React.Component {
constructor(props) {
super(props);
}

onTrigger = (event) => {
this.props.parentCallBack("This is data from the child");
event.preventDefault();
};

render() {
return (
<div>
<form onSubmit={this.onTrigger}>
<input type="submit" value="Submit" />
</form>
</div>
);
}
}

export default Child;

React and Redux

Reference

理解 React,但不理解 Redux,该如何通俗易懂的理解 Redux? - Starkwang的回答

柯里化 (Currying)

Reference:
Currying

Currying is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c).

Note: Currying does not call a function but only transform a function.

For a function with 2-argument -> f(a, b), the currying curry(f) for 2-argument f(a,b) translates it into a function that runs as f(a)(b)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function curry(f) { // curry(f) does the currying transform
return function(a) {
return function(b) {
return f(a, b);
};
};
}

// usage
function sum(a, b) {
return a + b;
}

let curriedSum = curry(sum);

alert( curriedSum(1)(2) ); // 3

The implementation is straightforwards - just 2 wrappers of functions.

  • curry(func f) is a wrapper of function(a)
  • Next level the new wrapper is returned function(b)

_.curry

The _.curry() from the lodash library - it returns a wrapper that allows a function to be called both normally and partially. (正常调用或者以偏函数的方式调用)