react 随笔记录
1.jsx
jsx:是一个javaScript的语法扩展,在react中配合使用jsx,可以更好的表述界面,表示ui页面及页面的一些变量
const element = <h1>Hello, world!</h1>;
babel会把jsx转义成React.createElement()函数调用
const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' );
ps:由于 JSX 会编译为 React.createElement
调用形式,所以 React
库也必须包含在 JSX 代码作用域内。这就是每次编写的时候都需要在顶部import React from 'react' 的原因。
2.函数组件和类组件
// 函数组件 function Welcome(props) { return <h1>Hello, {props.name}</h1>; } // 类组件 class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } }
函数组件和类组件的区别
Hook 避免了 class 需要的额外开支,像是创建类实例和在构造函数中绑定事件处理器的成本
符合语言习惯的代码在使用 Hook 时不需要很深的组件树嵌套。这个现象在使用高阶组件、render props、和 context 的代码库中非常普遍。组件树小了,React 的工作量也随之减少。
从类组件迁移到函数组件
constructor
:函数组件不需要构造函数。你可以通过调用useState
来初始化 state。如果计算的代价比较昂贵,你可以传一个函数给useState
。getDerivedStateFromProps
:改为 在渲染时 安排一次更新。shouldComponentUpdate
:详见React.memo
.render
:这是函数组件体本身。componentDidMount
,componentDidUpdate
,componentWillUnmount
:useEffect
Hook 可以表达所有这些(包括 不那么 常见 的场景)的组合。getSnapshotBeforeUpdate
,componentDidCatch
以及getDerivedStateFromError
:目前还没有这些方法的 Hook 等价写法,但很快会被添加。
3.setState
setState的更新可能是异步的,所以当setState({})对于数据进行更新后,可能不会得到你想要的值,可能没有立即更新
setState在合成事件和钩子函数中表现为异步,在原生事件和setTimeout中表现为同步
出于性能考虑,setState()会把多次更新合并为一次提交
this.props,this.state可能会异步更新,不要根据他们的值来进行更新,可以通过接受函数的形式来进行更新
// Wrong this.setState({ counter: this.state.counter + this.props.increment, }); // Correct this.setState((state, props) => ({ counter: state.counter + props.increment }));
4.事件处理机制
(1)react 事件处理机制与原生html有所不同
// 原生 <button onclick="activateLasers()"> Activate Lasers </button> // React采用驼峰命名 <button onClick={activateLasers}> Activate Lasers </button>
(2)对于默认行为的禁用
// 原生事件:通过return false阻止默认行为 <a href="#" onclick="console.log('The link was clicked.'); return false"> Click me </a> // react: 通过e.preventDefault()阻止默认行为 function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); }
类组件中绑定事件处理函数,需要注意this的绑定问题
// 1.通过bind手动对this进行绑定 this.handleClick = this.handleClick.bind(this); // 2.绑定的函数为箭头函数 <button onClick={this.handleClick}> Click me </button> handleClick = () => { console.log('this is:', this); } // 3.在回调函数中使用箭头函数 // 这里可以传参e, (e) => this.handleClick(e),e是一个合成事件 <button onClick={() => this.handleClick()}> Click me </button>
5.受控组件与非受控组件
受控组件:表单类的元素,使用react的state作为数据源,并通过state的控制来进行控制表单
使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
非受控组件:表单数据通过dom节点来控制,可以使用ref来获得表单数据
受控组件和非受控组件的对比:
特征 | 非受控组件 | 受控组件 |
---|---|---|
一次性价值检索(例如在提交时) | ✅ | ✅ |
提交时验证 | ✅ | ✅ |
即时字段验证 | ❌ | ✅ |
有条件地禁用提交按钮 | ❌ | ✅ |
强制输入格式 | ❌ | ✅ |
一个数据的多个输入 | ❌ | ✅ |
动态输入 | ❌ | ✅ |
6.context
Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
context使用的目的是为了在多个组件中都能使用公共的一些props
通过context,可以避免通过中间组件来传递props
// 1.首先创建一个context(light为默认值) const ThemeContext= React.createContext('light'); // 2.通过<ThemeContext.Provider>包裹传递给子组件 class App extends React.Component { render() { // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。 // 无论多深,任何组件都能读取这个值。 // 在这个例子中,我们将 “dark” 作为当前的值传递下去。 return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } } // 3.中间组件不用传递props // 中间的组件再也不必指明往下传递 theme 了。 function Toolbar() { return ( <div> <ThemedButton /> </div> ); // 4.嵌套的孙子组件可以读取value:dark class ThemedButton extends React.Component { // 指定 contextType 读取当前的 theme context。 // React 会往上找到最近的 theme Provider,然后使用它的值。 // 在这个例子中,当前的 theme 值为 “dark”。 static contextType = ThemeContext; render() { return <Button theme={this.context} />; } }
7.refs转发
//FancyButton
使用React.forwardRef
来获取传递给它的ref
,然后转发到它渲染的 DOMbutton
// 第二个参数ref只在React.forwardRef中存在,常规函数组件和类组件不存在
const FancyButton = React.forwardRef((props, ref) => ( <button ref={ref} className="FancyButton"> {props.children} </button> )); // 你可以直接获取 DOM button 的 ref: // 通过React.createRef()创建ref,传递给FancyButton组件 // 再传递给子button const ref = React.createRef(); <FancyButton ref={ref}>Click me!</FancyButton>;
refs提供了可以读取dom元素得一种方式
refs只能在类组件中使用,在函数组件中可以通过forwardRef进行使用
在函数组件中通过useRef声明refs
function CustomTextInput(props) { // 这里必须声明 textInput,这样 ref 才可以引用它 const textInput = useRef(null); function handleClick() { textInput.current.focus(); } return ( <div> <input type="text" ref={textInput} /> <input type="button" value="Focus the text input" onClick={handleClick} /> </div> ); }
8.高阶组件
高阶组件:是一个参数为组件,返回值为组件的函数
const EnhancedComponent = higherOrderComponent(WrappedComponent);
es: redux中的connect
高阶组件不应该改变原有组件而是要使用组合的方式
高阶组件接受组件作为参数,然后返回一个增强性的组件。
注意事项:
1.不要在render中使用高阶组件
2.拷贝组件上的静态方法
3.refs不会被转发
9.生命周期函数
挂载阶段:
constructor()
static getDerivedStateFromProps()
render()
componentDidMount()
更新阶段:
static getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
卸载阶段:
componentWillUnmount()
componentDidMount(): 会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。
componentDidUpdate(): 会在更新后会被立即调用。首次渲染不会执行此方法。当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。执行事件需要包含在条件语句中,否则会导致循环更新。
如果 shouldComponentUpdate()
返回值为 false,则不会调用 componentDidUpdate()
componentWillUnmount():会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount()
中创建的订阅等
componentDidMount()
中创建的订阅等shouldComponentUpdate():根据 shouldComponentUpdate()
的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。
shouldComponentUpdate()
的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。getDerivedStateFromProps():会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
getSnapshotBeforeUpdate():在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()
componentDidUpdate()
10.hooks
hooks使用规则:
- 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
- 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。
(1): useState()
useState
会返回一对值:当前状态和一个让你更新它的函数
// 声明一个叫 “count” 的 state 变量。 // 初始值为count,通过setCount来进行更新 const [count, setCount] = useState(0);
(2): useEffect()
useEffect
就是一个 Effect Hook,给函数组件增加了操作副作用的能力.
它跟 class 组件中的 componentDidMount
、componentDidUpdate
和 componentWillUnmount
具有相同的用途,只不过被合并成了一个 API
// 相当于 componentDidMount 和 componentDidUpdate: useEffect(() => { // 使用浏览器的 API 更新页面标题 document.title = `You clicked ${count} times`; }); // 通过返回值return 来实现 componentWillUnmount 清除作用 useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
可以只在更新的时候使用useEffect吗?
通过useRef()来进行更新
可以 使用一个可变的 ref 手动存储一个布尔值来表示是首次渲染还是后续渲染,然后在你的 effect 中检查这个标识。
const isInitialMount = useRef(true); useEffect(() => { if (isInitialMount.current) { isInitialMount.current = false; } else { // Your useEffect code here to be run on update } });
(3): 自定义hooks
(4): useContext
const value = useContext(MyContext);
接收一个 context 对象(React.createContext
的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider>
的 value
prop 决定。
const themes = { light: { foreground: "#000000", background: "#eeeeee" }, dark: { foreground: "#ffffff", background: "#222222" } }; const ThemeContext = React.createContext(themes.light); function App() { return ( <ThemeContext.Provider value={themes.dark}> <Toolbar /> </ThemeContext.Provider> ); } function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } function ThemedButton() { const theme = useContext(ThemeContext);
// 类组件中通过 static contextType = ThemeContext;
return ( <button style={{ background: theme.background, color: theme.foreground }}> I am styled by theme context! </button> ); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架