-
产品及方案 产品及方案
-
数据驱动型组织通过体系化的方法构建全域数据能力,实现数据驱动运营,重塑组织生产力
- 行业方案
- 典型方案
- 产品
-
数据驱动型组织
- 服务与支持
- 社区
- 合作伙伴
- 关于爱数
请选择咨询类型
扫码关注
爱数技术支持中心公众号
我们将在 24 小时之内联系你。
class Hello extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
function Hello(props) {
return <h1>Hello, {props.name}!</h1>;
}
function Hello(props) {
return <h1>Hello, {props.name}!</h1>;
}
import React, { useState } from 'react'
// const [state, setState] = React.useState(initialState)
const [stateN, setStateN] = React.useState(0)
React.useState(params) 设置第一个参数的初始值 。为了保证 memoizedState 的顺序与 React.useState() 正确对应,我们需要保证 Hooks 在最顶层调用,也就是不能在循环、条件或嵌套函数中调用。setXxx(newValue):参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值;
setXxx(value => newValue):参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值。
import React, { useState, useEffect } from "react";
React.useState() 通过 Object.is() 来判断 memoizedState 是否需要更新。
import React, {useState} from 'react';
import ReactDom from 'react-dom'
const App = ()=>{
console.log("useState test")
const [count,setCount] = useState(0)
const add = ()=>{
setCount(count+1)
}
return (
<div>
<div>{count}</div>
<button onClick={add}>+1</button>
</div>
)
}
ReactDom.render(<App/>,document.querySelector("#root"))
useEffect(() => {
// Async Action
}, [dependencies])
它接受2个参数,第一个是函数,第二个是数组,这里有三种情况:
如果第二个参数数组为空,它就是componentDidMount,只有第一次渲染;
如果第二个参数数组里面有值,它就是componentDidUpdate,只要其中任何一个state改变了,它就重新渲染;
如果没有第二个数组(只有一个函数),则只要有任何一个state改变,它就重新渲染。
const Person = ({ personId }) => {
const [loading, setLoading] = useState(true);
const [person, setPerson] = useState({});
useEffect(() => {
setLoading(true);
fetch(`https://swapi.co/api/people/${personId}/`)
.then(response => response.json())
.then(data => {
setPerson(data);
setLoading(false);
});
}, [personId])
if (loading === true) {
return <p>Loading ...</p>
}
return <div>
<p>You're viewing: {person.name}</p>
<p>Height: {person.height}</p>
<p>Mass: {person.mass}</p>
</div>
}
上面代码中,每当组件参数personId发生变化,useEffect()就会执行。组件第一次渲染时,useEffect()也会执行。
function Welcome(props) {
useEffect(() => {
document.title = `Hello, ${props.name}`;
}, [props.name]);
return <h1>Hello, {props.name}</h1>;
}
获取数据(data fetching)
事件监听或订阅(setting up a subscription)
改变 DOM(changing the DOM)
输出日志(logging)
下面是从远程服务器获取数据的例子。
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(() => {
const fetchData = async () => {
const result = await axios(
'https://hn.algolia.com/api/v1/search?query=redux',
);
setData(result.data);
};
fetchData();
}, []);
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}
export default App;
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
}, [props.source]);
上面例子中,useEffect()在组件加载时订阅了一个事件,并且返回一个清理函数,在组件卸载时取消订阅。
function App() {
const [varA, setVarA] = useState(0);
const [varB, setVarB] = useState(0);
useEffect(() => {
const timeoutA = setTimeout(() => setVarA(varA + 1), 1000);
const timeoutB = setTimeout(() => setVarB(varB + 2), 2000);
return () => {
clearTimeout(timeoutA);
clearTimeout(timeoutB);
};
}, [varA, varB]);
return {varA}, {varB};
}
上面的例子是错误的写法,副效应函数里面有两个定时器,它们之间并没有关系,其实是两个不相关的副效应,不应该写在一起。正确的写法是将它们分开写成两个useEffect()。
function App() {
const [varA, setVarA] = useState(0);
const [varB, setVarB] = useState(0);
useEffect(() => {
const timeout = setTimeout(() => setVarA(varA + 1), 1000);
return () => clearTimeout(timeout);
}, [varA]);
useEffect(() => {
const timeout = setTimeout(() => setVarB(varB + 2), 2000);
return () => clearTimeout(timeout);
}, [varB]);
return {varA}, {varB};
}
useState 和 useEffect 支持写多个,例如:
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
useEffect(() => {
},[])
useEffect(() => {
},[xxx])
3、useMemo
useMemo(fn, arr); //当数组中的其中一个元素,发生变化时,就会调用 函数 。
const nameStr = useMemo(() => genName(name),[name])
// 表示,当name发生变化时,才会调用 () => genName(name)函数
特点
//父组件:ParentFn.jsx
import { useState } from "react";
import SonFn from "./Son";
export default () => {
console.log("父组件");
const [name, setName] = useState('Sam')
const [age, setAge] = useState(12)
return (
<>
<h1>useMemo</h1>
<button
onClick={() => setName(name + "1")}>修改name</button>
<button
onClick={() => setAge(age + 1)}>修改age</button>
<hr />
<SonFn name={name} age={age} />
</>
)
}
//子组件:SonFn.jsx
import React, { memo, useMemo } from 'react'
const SonFn = ({ name, age }) => {
console.log("子组件");
function isAdult(age1) {
return age1 >= 18 ? "已成年" : "未成年";
}
// 写在函数式组件里的 “函数调用代码” 。
// 只要函数式组件重新渲染了,那么isAdult函数就会被调用一次。即使只是改了name的值。
// let adultStr = isAdult(age);
//现在,加上useMemo后,表示只有age发生变化,才调用isAdult函数。
let adultStr = useMemo(() => {
console.log("age更新了才会执行")
return isAdult(age);
}, [age]);
return (
<div>
<h5>子组件(函数式组件)</h5>
<p>姓名:{name}</p>
<p>年龄:{age}</p>
<p>是否成年:{adultStr}</p>
</div>
)
}
export default memo(SonFn);
useMemo( ( ) => (x) => console.log( x ))
这是一个返回函数的函数。
useCallback(x=>console.log(x), [m]) 等价于 useMemo(()=>x=>console.log(x),[m])
useCallback和useMemo的区别:
import React, { memo, useCallback, useState } from "react";
const HookTest = memo(() => {
const [count, setcount] = useState(0);
const [num, setnum] = useState(100);
const showCount = () => {
console.log("useCallback test,", count + "$");
};
return (
<div>
<h2>HookTest:useCallback----useMemo</h2>
<h3>useCallBack</h3>
<h4>
count:{count}---num:{num}
</h4>
<button onClick={showCount}>showCount</button>
<button onClick={(e) => setcount(count + 3)}>+3</button>
<button onClick={(e) => setnum(num * 10)}>*10</button>
);
});
export default HookTest;
const showCount = () => {
console.log("useCallback test", count + "$");
};
const showCount = useCallback(() => {
console.log("useCallback test", count + "$");
}, [count]);
那么现在的 showCount 和之前的又有什么不一样呢?
const refContainer = useRef(initialValue);
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。
// App.jsx
/*
1.需要引入createContext,useContext
2.通过createContext来创建句柄
3.Context.Provider来确定共享范围
4.通过value来分发内容
5.在子组件中通过useContext(Context句柄)来获取数据
*/
import React, { useState, createContext, useContext } from "react";
const C = createContext(null);
function App() {
console.log("App 执行了");
const [n, setN] = useState(0);
return (
<C.Provider value={{ n, setN }}>
<div className="App">
<Father />
</div>
</C.Provider>
);
}
function Father() {
const { n, setN } = useContext(C);
return (
<div>
我是Father n: {n} <Child />
</div>
);
}
function Child() {
const { n, setN } = useContext(C);
const onClick = () => {
setN((i) => i + 1);
};
return (
<div>
我是Son 我得到的 n: {n}
<button onClick={onClick}>+1</button>
</div>
);
}
export default App;
const [state, dispatch] = useReducer(reducer, initialArg, init);
initialArg为初始数据;
import React, { useReducer } from 'react';
const App = () => {
const [state, dispath] = useReducer((state, action) => {
console.log(state);
switch (action.type) {
case 'increment':
return state + 1;
case 'decrement':
return state - 1;
default:
return state;
}
}, 0);
return (
<div className='App'>
<button onClick={() => dispath({ type: 'increment' })}>increment</button>
<button onClick={() => dispath({ type: 'decrement' })}>decrement</button>
<p>{state}</p>
</div>
);
};
export default App;
const initialState = {
n: 0,
};
const reducer = (state, action) => {
if (action.type === "add") {
/* 规则与useState一样必须返回新的对象,不然变量值不会改变 */
return { n: state.n + action.number };
} else if (action.type === "multi") {
return { n: state.n * action.number };
} else {
throw new Error("unknown type!");
}
};
/* 在函数组件中使用useReducer */
const App = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const onclick1 = () => {
dispatch({ type: "add", number: 1 });
};
const onclick2 = () => {
dispatch({ type: "add", number: 2 });
};
const onclick3 = () => {
dispatch({ type: "multi", number: 2 });
};
return (
<div className="App">
<h1>n:{state.n}</h1>
<button onClick={onclick1}>+1</button>
<button onClick={onclick2}>+2</button>
<button onClick={onclick3}>x2</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
示例3:使用 useReducer 写一个表单提交
- 创建初始值的状态initialState
- 创建所有对状态的操作reducer(state,action)
- 传给useReducer,得到读和写的接口
- 调用写({'type':'操作类型'})
const initialState = {
name: "",
age: 18,
nationality: "汉族",
};
const reducer = (state, action) => {
switch (action.type) {
case "patch":
return { ...state, ...action.formData };
case "reset":
return initialState;
default:
throw new Error("unknown type!");
}
};
/* 在函数组件中使用useReducer */
const App = () => {
const [formData, dispatch] = useReducer(reducer, initialState);
const onSubmit = () => {
alert("你点击了提交按钮");
};
const onReset = () => {
dispatch({ type: "reset" });
};
return (
<form onSubmit={onSubmit} onReset={onReset}>
<div>
<label>
姓名
<input
type="text"
value={formData.name}
onChange={(e) => {
dispatch({ type: "patch", formData: { name: e.target.value } });
}}
/>
</label>
</div>
<div>
<label>
年龄
<input
type="number"
value={formData.age}
onChange={(e) => {
dispatch({ type: "patch", formData: { name: e.target.value } });
}}
/>
</label>
</div>
<div>
<label>
民族
<input
type="text"
value={formData.nationality}
onChange={(e) => {
dispatch({
type: "patch",
formData: { nationality: e.target.value },
});
}}
/>
</label>
</div>
<div>
<button type="submit">提交</button>
<button type="reset">重置</button>
</div>
<hr />
{JSON.stringify(formData)}
</form>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
在输入框中输入一些东西,下面会及时的更新显示出来的输入的数据。
const store = {
n: 0,
m: 0,
p: 0,
};
const reducer = (state, action) => {
switch (action.type) {
case "setN":
return { ...state, n: state.n + action.number };
case "setM":
return { ...state, m: state.m + action.number };
case "setP":
return { ...state, p: state.p + action.number };
default:
throw new Error("unknown type!");
}
};
/* 创建上下文对象--模拟一个Redux的作用域 */
const Context = React.createContext(null);
const App = () => {
const [state, dispatch] = React.useReducer(reducer, store);
return (
<Context.Provider value={{ state, dispatch }}>
<N />
<M />
<P />
</Context.Provider>
);
};
const N = () => {
const { state, dispatch } = React.useContext(Context);
const addClick = () => {
dispatch({ type: "setN", number: 1 });
};
return (
<div>
<h1>N组件</h1>
<div>n:{state.n}</div>
<div>m:{state.m}</div>
<div>p:{state.p}</div>
<button onClick={addClick}>+1</button>
</div>
);
};
const M = () => {
const { state, dispatch } = React.useContext(Context);
const addClick = () => {
dispatch({ type: "setM", number: 2 });
};
return (
<div>
<h1>M组件</h1>
<div>n:{state.n}</div>
<div>m:{state.m}</div>
<div>p:{state.p}</div>
<button onClick={addClick}>+2</button>
</div>
);
};
const P = () => {
const { state, dispatch } = React.useContext(Context);
const addClick = () => {
dispatch({ type: "setP", number: 3 });
};
return (
<div>
<h1>P组件</h1>
<div>n:{state.n}</div>
<div>m:{state.m}</div>
<div>p:{state.p}</div>
<button onClick={addClick}>+3</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
在一番对 n,m,p 数据的操作后,所有组件的值都变化了更新。
const usePerson = (personId) => {
const [loading, setLoading] = useState(true);
const [person, setPerson] = useState({});
useEffect(() => {
setLoading(true);
fetch(`https://swapi.co/api/people/${personId}/`)
.then(response => response.json())
.then(data => {
setPerson(data);
setLoading(false);
});
}, [personId]);
return [loading, person];
};
上面代码中,usePerson()就是一个自定义的 Hook。
const Person = ({ personId }) => {
const [loading, person] = usePerson(personId);
if (loading === true) {
return <p>Loading ...</p>;
}
return (
<div>
<p>You're viewing: {person.name}</p>
<p>Height: {person.height}</p>
<p>Mass: {person.mass}</p>
</div>
);
};
请就本文对您的益处进行评级: