一、什么是React
React 是一个用于构建用户界面(UI)的 JavaScript 库,它的特点:
1、声明式:只需要描述UI看起来是什么样式,就跟写HTML一样,只负责渲染UI ;
2、基于组件:组件是React最重要的内容;
二、JSX语法规则
1、定义虚拟dom时不要写引号;
2、标签中混入js表达式时要加{};
3、样式的类名指定用className;
4、内联样式用style={{key:value}}的形式;
5、只有一个根标签;
6、标签必须闭合;
7、标签首字母:
(1)若首字母是小写字母:则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错;
(2)若首字母是大写字母:react就去渲染对应的组件,若组件未定义则报错;
三、React中定义组件
1、类组件
使用es6的class语法创建组件
a. 类组件名称必须是大写字母开头
b. 类组件应该继承 React.Component 父类,父类中提供了很多的方法和属性
c. 类组件必须提供render方法
d. render方法必须有返回,表示组件结构
类组件工作流程:
1、第一步,React解析组件标签,找到对应组件
2、发现组件是类定义的,然后new一个该类实例,并通过实例调用了原型上的render方法。
3、将render方法返回的虚拟DOM转为真实DOM,最后呈现在页面中。
2、函数组件
a. 使用js的函数或者箭头函数创建的组件
b. 函数组件的名称必须大写字母开头,
c. 必须有返回值,表示组件结构
函数组件渲染流程:
1、ReactDOM解析组件标签,找到了组件。
2、发现组件是使用函数式定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
类组件、函数组件区别:
1、类组件有自己的实例,函数组件没有实例,所以类组件可以通过this去操作,它有自己的生命周期,可以使用state。
2、函数组件是无状态组件,但是它可以通过react hooks实现有状态组件,函数组件没有this,不能使用生命周期钩子。
四、React事件处理
1、通过onXxxx属性指定事件处理函数,注意大小写
(1)React使用的是自定义事件,而不是使用的原生dom事件;
(2)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素);
2、通过event.target得到发生事件的dom元素对象
五、React中收集表单数据
1、受控组件
React受控组件是一种由React状态控制的组件,通常使用 state 来控制和修改组件的值,当组件的值发生变化时,React状态更新,组件重新渲染,表单文本框的值始终与React状态值保持同步。
受控组件更容易进行验证和处理,有更好的可预测性,但是也因此受控组件需要写更多的代码,由于每次组件的值发生变化时,它都会更新React状态并重新渲染,数据较大时可能会影响性能。
// 受控组件class ControlledInput extends React.Component { constructor(props) { super(props); this.state = { value: '' }; } handleChange(event) { this.setState({ value: event.target.value }); } render() { return ( <div style={{ marginTop: '20px', borderTop: '1px solid #ccc', paddingTop: '15px' }}> <h3 >受控组件</h3> <input style={{ height: '32px', marginTop: '15px' }} type="text" value={this.state.value} onChange={(e) => this.handleChange(e)} /> </div> ); }}
2、非受控组件
React非受控组件是一种不由React状态控制的组件。在非受控组件中,组件的值不由React状态管理,通常使用 refs 来访问 DOM 元素获取值。
非受控组件可以更快的更新,代码更少,但是也更不容易进行验证和处理,相对受控组件而言,当组件的值发生变化时,因为它不会更新react状态也不会重新渲染,可能会导致应用程序的行为更加不可预测。
class UncontrolledInput extends Component { constructor(props) { super(props); this.inputRef = React.createRef(); } handleClick() { console.log('Input value:', this.inputRef.current.value); } render() { return ( <div style={{ marginTop: '20px', borderTop: '1px solid #ccc', paddingTop: '15px' }}> <h3>非受控组件</h3> <input style={{ height: '32px' }} type="text" ref={this.inputRef} /> <button style={{ margin: '10px' }} onClick={() => this.handleClick()}>Click</button> </div> ); }}
受控组件和非受控组件的区别:
React受控组件和非受控组件之间的最大区别是组件的值是由React状态控制还是由DOM节点控制。 在受控组件中,组件的值由React状态控制,当组件的值发生变化时,React状态将更新,组件将重新渲染以反映新值。
在非受控组件中,组件的值由DOM节点控制,当组件的值发生变化时,它将直接反映在DOM节点上,而不会更新React状态,这使得非受控组件可以更快地更新,但也使得验证和处理组件的值更加困难。
六、ref的使用
Refs提供了一种方式,允许我们访问DOM节点或者在render方法中创建的React元素。
ref的使用方式:
1) 字符串形式的ref:存在效率问题,不推荐使用(类组件中通过this.refs.refname.value访问);
2) 回调形式的ref:在组件上挂载函数,函数的入参是DOM节点或组件实例(<input ref={c => this.input1 = c} type="text" placeholder="回调形式的ref" />),ref中的回调函数将自身节点放在了组件节点上。
3) 使用React.createRef()创建:通常在 React 组件的构造函数中定义,并通过 ref 属性附加到 React 元素;
注:1、使用React.forwardRef函数可以将父组件的ref传入子组件;
2、函数组件中可以使用useRef钩子。
在 React 中使用 ref 注意事项:
1、避免过度使用 ref
不要在组件中大面积使用 ref,组件应该越“无状态”越好。ref 主要适用于必须访问 DOM 元素的特殊场景。
2、 不要在函数组件中暴露 ref
函数组件没有实例,它的 ref 会在每次渲染时发生变化,可能导致奇怪的 bug。
3、 ref 不会自动绑定
当组件重新渲染时,ref 不会自动变化,需要在组件加载和卸载时手动更新。
4、 将 ref 传递给 DOM 元素时要注意泄露风险
如果组件被卸载但其 ref 仍在使用,会导致内存泄露。可以在组件卸载时手动将 ref 的 current 属性置为 null。
5、避免在渲染期间设置 ref
不要在函数组件主体或 class 组件 render 方法中设置 ref,这可能导致 ref 不一致。应在加载后才设置 ref。
6、 将 ref 回调与 useEffect 配合使用。
可以在 useEffect 中设置或重置 ref,以避免上述问题。 在严格模式下使用 ref 会抛出警告,需要用 React.forwardRef 处理。