核心概念
1. JSX
- JSX是javascript的语法扩展,让我们可以在JS中编写常规html代码,在JSX中可以在大括号
{}
内放置任何有效的javascript表达式。 - JSX也是一个表达式,可以在
if
和for
循环代码块中使用JSX。 - 通过引号将属性值指定为字符串字面量,使用大括号将属性值指定为j s表达式。
- React DOM 使用
camelCase
(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。例如在JSX中class变为className。
const name = 'Jade';
const element = <div>
<h1 className='weclome'>Hello, {name}</h1>
<input type='text' defaultValue={name} />
</div>;
ReactDOM.render(
element,
document.getElementById('root')
);
2. props
- 当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性以及子组件转换为单个对象传递给组件,这个对象被称之为 “props”。
- 组件无论是使用函数声明还是class声明,都不能修改自身的 props,props为只读。
3. State
- state是组件私有化,且完全受控于当前组件,简单说,完全props,state在组件内可以随意修改。定义state应该在class构造函数
constructor
中,state可以传递给子组件,数据是向下流动。 - 关于修改state,应该使用
setState()
,而不是直接赋值。this.setState({name: 'Jade'}); //correct
this.state.name = 'jade'; // wrong
-
setState()
为异步,多个setState()
会合并为一个调用。所以最好不要依赖它们的值来更新下一个状态。 - 关于异步的问题,可以让
setState()
接受一个函数来解决,该函数接受两个参数,用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数。
4. 事件处理
-
不能通过
return false;
阻止默认行为,只能是e.preventDefault()
。 -
JSX中回调问题,事件回调必须绑定
this
,不然回调中this
为undefined
。原因在于js函数工作原理:const obj = { name: 'Jade', say: function () { console.log(this); } }; const test = obj.say; obj.say(); // {name: "Jade", say: ƒ} test(); // undefined
在js中,传递一个函数名给一个变量,然后在变量后加上()调用这个方法,此时方法内部的this的指向就丢失。在React中,OnClick其实就是一个中间变量,所以
this
会丢失。 -
关于事件回调中
this
丢失的解决办法有以下:- 使用
bind
绑定this
,<a onClick={this.click.bind(this)}>点击</a>
。 - 使用箭头函数定义事件回调
this.click = () => { //do something }
- 使用箭头函数调用事件回调
<a onClick={() => this.click()}>点击</a>
- 使用
-
事件传递参数的方法有两种,分别是通过箭头函数和
bind
,事件对象e会被视为第二个参数,不同的是,箭头函数的方式必须显式的传入e,bind
则不需要,如下:-
<a onClick={(e) => this.click(id, e)}>点击</a>
-
<a onClick={this.click.bind(this, id)}>点击</a>
-
5. 表单
- 受控组件:表单中存在一个input,其value值必须是我们设置在constructor构造函数中的state的值,通过onChange事件改变state中的值,最终形成一个循环的回路影响。
- 非受控组件:非受控也就意味着我可以不需要设置它的state属性,而通过ref来操作真实的DOM。
6. 组件之间通讯
-
父子通讯:
// Context 可以让我们无须明确地传遍每一个组件,就能将值深入传递进组件树。 // 使用场景: 嵌套多层的组件,且每层组件可能都会用到某个变量 // 缺点:导致组件的复用性降低 const NameContext = React.createContext('Jade'); // 默认值‘Jade’ class App extends React.Component { render() { return ( // 使用Provider,将变量传递给下面的所有组件 <NameContext.provider value='Jadeee'> <PageHeader /> </NameContext> ) } } class PageHeader extends React.Component { render() { // 中组件不用在手动传递了 return <UserName /> } } class UserName extends React.Component { static contentType = NameContext; render() { return <p> {this.context} </P> } }
// 父子通讯主要通过props传递参数,数据自上而下流动,实现父子通讯 class ChildrenComponent extends React.Component { constructor(props) { super(props); } render() { return ( {/* 接受从父组件传递而来的title */} <h1> {this.props.title} </h1> ) } } class ParentComponent extends React.Component { constructor(props) { super(props); this.state = { title: '标题' } } render() { return ( {/* 将this.state.title传递给子组件 */} <ChildrenComponent title={this.state.title} /> ) } }
-
子父通讯:
class ChildrenComponent extends React.Component { constructor(props) { super(props); this.state = { name: 'children component' } } clickBtn() { // 调用父组件方法并将参数传递给父组件 this.props.onClickChildren(this.state.name); } render() { return ( <button type="button" onClick={this.clickBtn.bind(this)}> Click Me! </button> ) } } class ParentComponent extends React.Component { constructor(props) { super(props); } // 子组件调用,val参数为子组件传递过来 onClickChildren(val) { console.log(val); // children component } render() { return ( <div> {/* 将onClickChildren()方法作为props传递给子组件 */} <ChildrenComponent onClickChildren={this.onClickChildren.bind(this)} /> </div> ) } }
-
子子通讯:
- eventBus
- Redux
网友评论