首先保证安装Node >= 6 和 npm >= 5.2版本以上的node.js环境
然后执行以下的代码,创建一个基本React-App项目
npx create-react-app my-app cd my-app npm start 删除新项目 src/ 文件夹中的所有文件。这是我们接下来要写代码的区域,在接下来的教程中将会一步步补充进来。注意:不要删除整个src文件夹,只删除文件夹中原始文件。我们将在下一步中用此项目的示例替换默认源文件。 cd src # 如果你使用 Mac 或者 Linux: rm -f * # 或者, 如果你使用 Windows: del * # 然后,切换回项目文件夹 cd .. 在 src/ 文件夹中添加一个名为 index.css 的文件,这个文件中包含的 CSS代码 。在 src/ 文件夹中添加一个名为 index.js 的文件,这个文件中包含的 JS代码 。然后在 src/ 文件夹 index.js 的文件中,在其顶部添加以下 3 行代码: import React from 'react'; import ReactDOM from 'react-dom'; import './index.css';现在,如果您在项目文件夹中运行 npm start,并在浏览器中打开 http://localhost:3000 ,你应该看到一个空的字段。
JSX 防止注入攻击,默认情况下, 在渲染之前, React DOM 会格式化(escapes) JSX中的所有值. 从而保证用户无法注入任何应用之外的代码. 在被渲染之前,所有的数据都被转义成为了字符串处理。 以避免 XSS(跨站脚本) 攻击。
Babel 将JSX编译成 React.createElement() 调用。以下连个代码是完全一样的。
const element = ( <h1 className="greeting"> Hello, world! </h1> ); const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' );react 元素是 不可突变(immutable) 的. 一旦你创建了一个元素, 就不能再修改其子元素或任何属性。一个元素就像电影里的一帧: 它表示在某一特定时间点的 UI 。就我们所知, 更新 UI 的唯一方法是创建一个新的元素, 并将其传入 ReactDOM.render() 方法.
React DOM 会将元素及其子元素与之前版本逐一对比, 并只对有必要更新的 DOM 进行更新, 以达到 DOM 所需的状态。
从定义上来说, 组件就像JavaScript的函数。组件可以接收任意输入(称为”props”), 并返回 React 元素,用以描述屏幕显示内容。
函数式组件和类组件
//函数式 function Welcome(props) { return <h1>Hello, {props.name}</h1>; } //类组件 class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } 元素也可以代表用户定义的组件,组件名称总是以大写字母开始。当 React 遇到一个代表用户定义组件的元素时,它将 JSX 属性以一个单独对象的形式传递给相应的组件。 我们将其称为 “props” 对象。 function Welcome(props) { return <h1>Hello, {props.name}</h1>; } const element = <Welcome name="Sara" />; ReactDOM.render( element, document.getElementById('root') ); //我们调用了 ReactDOM.render() 方法并向其中传入了 <Welcome name="Sara" /> 元素。 //React 调用 Welcome 组件,并向其中传入了 {name: 'Sara'} 作为 props 对象。 //Welcome 组件返回 <h1>Hello, Sara</h1>。 //React DOM 迅速更新 DOM ,使其显示为 <h1>Hello, Sara</h1>。组件可以在它们的输出中引用其它组件
不要害怕把一个组件分为多个更小的组件。
Props 是只读的,无论你用函数或类的方法来声明组件, 它都无法修改其自身 props
用类定义的组件有一些额外的特性。 这个”类专有的特性”, 指的就是局部状态。state 和 props 类似,但是它是私有的,并且由组件本身完全控制。
把函数式组件转化为类组件
//1.创建一个继承自 React.Component 类的 ES6 class 同名类。 //2.添加一个名为 render() 的空方法。 //3.把原函数中的所有内容移至 render() 中。 //4.在 render() 方法中使用 this.props 替代 props。 //5.删除保留的空函数声明。 class Clock extends React.Component { render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.props.date.toLocaleTimeString()}.</h2> </div> ); } 生命周期方法componentDidMount() 钩子在组件输出被渲染到 DOM 之后运行。
componentWillUnmount() 钩子在产生的 DOM 被销毁时运行
不要直接修改 state(状态),用 setState() 代替,唯一可以分配 this.state 的地方是构造函数。 //例如,这样将不会重新渲染一个组件: this.state.comment = 'Hello'; //用 setState() 代替: this.setState({comment: 'Hello'}); state(状态) 更新可能是异步的,React 为了优化性能,有可能会将多个 setState() 调用合并为一次更新。this.props 和 this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)。 //以下代码可能导致 counter(计数器)更新失败: this.setState({ counter: this.state.counter + this.props.increment, }); //要解决这个问题,应该使用第 2 种 setState() 的格式,它接收一个函数,而不是一个对象。该函数接收前一个状态值作为第 1 个参数, 并将更新后的值作为第 2 个参数: this.setState((state, props) => ({ counter: state.counter + props.increment }));当你调用 setState(), React 将合并你提供的对象到当前的状态中。
无论作为父组件还是子组件,它都无法获悉一个组件是否有状态,同时也不需要关心另一个组件是定义为函数组件还是类组件。这就是 state(状态) 经常被称为 本地状态 或 封装状态的原因。 它不能被拥有并设置它的组件 以外的任何组件访问。
一个组件可以选择将 state(状态) 向下传递,作为其子组件的 props(属性):
通过 React 元素处理事件跟在 DOM 元素上处理事件非常相似。但是有一些语法上的区别:
React 事件使用驼峰命名,而不是全部小写。
通过 JSX , 你传递一个函数作为事件处理程序,而不是一个字符串。
在 React 中你不能通过返回 false(即 return false; 语句) 来阻止默认行为。必须明确调用 preventDefault
当使用 React 时,你一般不需要调用 addEventListener 在 DOM 元素被创建后添加事件监听器。相反,只要当元素被初始渲染的时候提供一个监听器就可以了。
一般情况下,如果你引用一个后面没跟 () 的方法,例如 onClick={this.handleClick} ,那你就应该 绑定(bind) 该方法。 如果调用 bind 令你烦恼,有两种方法可以解决这个问题。
代码块 //方法一 使用实验性的 属性初始化语法 ,那么你可以使用属性初始值设置来正确地 绑定(bind) 回调: class LoggingButton extends React.Component { // 这个语法确保 `this` 绑定在 handleClick 中。 handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } } //方法二 没有使用属性初始化语法,可以在回调中使用一个 箭头函数 class LoggingButton extends React.Component { handleClick() { console.log('this is:', this); } render() { // This syntax ensures `this` is bound within handleClick return ( <button onClick={(e) => this.handleClick(e)}> Click me </button> ); } }
React 中的条件渲染就和在 JavaScript 中的条件语句一样。使用 JavaScript 操作符如 if 或者条件操作符来创建渲染当前状态的元素,并且让 React 更新匹配的 UI 。
可以用变量来存储元素。这可以帮助您有条件地渲染组件的一部分,而输出的其余部分不会更改。
使用逻辑 && 操作符的内联 if 用法,可以 在JSX中嵌入任何表达式 ,方法是将其包裹在花括号中。这也包括 JavaScript 逻辑 && 运算符。因为在 JavaScript 中, true && expression 总是会评估为 expression ,而 false && expression 总是执行为 false 。
使用条件操作符的内联 If-Else,另一个用于条件渲染元素的内联方法是使用 JavaScript 的条件操作符 condition ? true : false
在极少数情况下,您可能希望组件隐藏自身,即使它是由另一个组件渲染的。为此,返回 null 而不是其渲染输出。
键(Keys),帮助 React 标识哪个项被修改、添加或者移除了。数组中的每一个元素都应该有一个唯一不变的键(Keys)来标识:挑选 key 最好的方式是使用一个在它的同辈元素中不重复的标识字符串。
keys 只在数组的上下文中存在意义。如果你提取 一个 ListItem 组件,应该把 key 放置在数组处理的 元素中,不能放在 ListItem 组件自身中的
根元素上。在数组中使用的 keys 必须在它们的同辈之间唯一。然而它们并不需要全局唯一。我们可以在操作两个不同数组的时候使用相同的 keys :
键是React的一个内部映射,但其不会传递给组件的内部。如果你需要在组件中使用相同的值,可以明确使用一个不同名字的 prop 传入。
//Post 组件可以读取 props.id,但是不能读取 props.key 。 const content = posts.map((post) => <Post key={post.id} id={post.id} title={post.title} /> ); 在 JSX 中嵌入 map(),JSX允许在大括号中嵌入任何表达式,因此可以 内联 map() function NumberList(props) { const numbers = props.numbers; return ( <ul> {numbers.map((number) => <ListItem key={number.toString()} value={number} /> )} </ul> ); }在 React 中, 的赋值使用 value 属性替代。
注意,选项是初始化选中的,因为它的 selected 属性。React 中,并不使用这个 selected 属性,而是在根 select 标签中使用了一个 value 属性。这使得受控组件使用更方便。您可以将一个数组传递给 value 属性,允许你在 select 标签中选择多个选项。
当您需要处理多个受控的 input 元素时,您可以为每个元素添加一个 name 属性,并且让处理函数根据 event.target.name 的值来选择要做什么。
比较成熟的表单控件方法,可以在formilk学习。
通常情况下,同一个数据的变化需要几个不同的组件来反映。我们建议提升共享的状态到它们最近的祖先组件中
在 React 中,共享 state(状态) 是通过将其移动到需要它的组件的最接近的共同祖先组件来实现的。 这被称为“状态提升(Lifting State Up)”。
在一个 React 应用中,对于任何可变的数据都应该循序“单一数据源”原则。通常情况下,state 首先被添加到需要它进行渲染的组件。然后,如果其它的组件也需要它,你可以提升状态到它们最近的祖先组件。你应该依赖 从上到下的数据流向 ,而不是试图在不同的组件中同步状态
React 拥有一个强大的组合模型,我们建议使用组合而不是继承以实现代码的重用。
一些组件在设计前无法获知自己要使用什么子组件,尤其在 Sidebar 和 Dialog 等通用 “容器” 中比较常见。我们建议这种组件使用特别的 children prop 来直接传递 子元素到他们的输出中:
function FancyBorder(props) { return ( <div className={'FancyBorder FancyBorder-' + props.color}> {props.children} </div> ); } function WelcomeDialog() { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> Welcome </h1> <p className="Dialog-message"> Thank you for visiting our spacecraft! </p> </FancyBorder> ); } 在一个组件中你可能需要多个 “占位符” 。在这种情况下,你可以使用自定义的 prop(属性),而不是使用 children : function SplitPane(props) { return ( <div className="SplitPane"> <div className="SplitPane-left"> {props.left} </div> <div className="SplitPane-right"> {props.right} </div> </div> ); } function App() { return ( <SplitPane left={ <Contacts /> } right={ <Chat /> } /> ); } 我们可能说一个 WelcomeDialog 是 Dialog 的一个特殊用例。在React中,也可以使用组合来实现,一个偏“特殊”的组件渲染出一个偏“通用”的组件,通过 props(属性) 配置它 function Dialog(props) { return ( <FancyBorder color="blue"> <h1 className="Dialog-title"> {props.title} </h1> <p className="Dialog-message"> {props.message} </p> </FancyBorder> ); } function WelcomeDialog() { return ( <Dialog title="Welcome" message="Thank you for visiting our spacecraft!" /> ); }确定 UI state(状态) 1.是否通过 props(属性) 从父级传入? 如果是这样,它可能不是 state(状态) 。 2.是否永远不会发生变化? 如果是这样,它可能不是 state(状态)。 3.是否可以由组件中其他的 state(状态) 或 props(属性) 计算得出?如果是这样,则它不是 state(状态)。
react生命周期
React生命周期主要包括三个阶段:初始化阶段、运行中阶段和销毁阶段,在React不同的生命周期里,会依次触发不同的钩子函数
详细链接见:图解ES6中的React生命周期