VSCode配置语法高亮
安装Babel JavaScript
插件
创建项目
npx create-react-app my-app
cd my-app
npm start
其他还有
npm run build
打包项目
npm run eject
弹射配置文件
此外在package.json
中添加"homepage": ".",
可以让打包后的资源路径都变为相对index.html
JSX
JSX并不是单纯的将{}
中内容替换后的HTML
- 属性名均为小驼峰且部分有所变化,如JSX 里的
class
变成了className
,而tabindex
则变为tabIndex
。 - 自定义属性依然为
data-*
形式,并可通过dom元素的dataset
属性获取 -
{}
中的内容默认会进行转义,因此不用担心XSS攻击 - 没有内容的标签可以使用
/>
来闭合。 - style内容变为对象形式,且key变为小驼峰
- 图片等资源可以通过以下四种方式引入
import Img from "./images/1.png" <img src={Img} alt=""/>
<img src={require("./images/1.png")} alt=""/>
style={{background:"url("+require("./images/1.png")+")" }}
-
<img src={process.env.PUBLIC_URL + "/logo512.png"} />;
其中process.env.PUBLIC_URL
等同于index.html中的%PUBLIC_URL%
表示public目录,start和build时webpack会将其替换为实际路径
所有JSX其实都是React.createElement()
的语法糖,通过Babel 可以进行转义。
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
等同于
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
渲染
通过render
方法将react元素初始化并渲染到页面上
ReactDOM.render(
element,
document.getElementById('root')
);
其中element可以直接为上文中新建的元素,也可以为元素对应的组件标签,如<MyTest />
组件
接受任意的属性作为入参(即 props
),并返回用于描述页面展示内容的 React 元素。
- 组件必须为大驼峰命名,小写字母开头的组件会被视为原生 DOM 标签。
- 通常将 App 组件 作为每个新的 React 应用程序的顶层组件。
- 父元素需传元素给子元素时,可以在子组件标签间写入元素并通过
props.children
获取,或直接将待传入元素作为属性赋予子元素并通过props
获取(类似插槽slot)
函数组件与 class 组件
function Welcome(props) {
return element;
}
class组件中每次组件更新都会重新触发render
class Welcome extends React.Component {
render() {
return element;
}
}
react元素也可以是自定义组件
const name="Sara";
function Welcome_Fn(props) {
function speak(e) {
e.preventDefault();
alert(this.props.name);
}
return <h1 onClick={speak}>Hello, {props.name}</h1>;
}
class Welcome_Class extends React.Component {
speak() {
alert(this.props.name);
}
render() {
return <div onClick={onClick=()=>this.speak()}>Hello, {this.props.name}</div>;
}
}
const element = <Welcome_Class name="Sara" />;
ReactDOM.render(
//element,
//<Welcome_Class/>,
//<Welcome_Fn/>,
//new Welcome_Class({name}),
//new Welcome_Fn({name}),
<div>Hello, {name}</div>,
document.getElementById('root')
);
props
- 组件的属性传入为
props
- 所有 React 组件都必须像纯函数(入参不会被函数内容修改)一样保护它们的
props
不被更改,会发生变化的数据应使用state
。
state
- 与
props
类似,但是state
是私有的,并且完全受控于当前组件。 - 无需使用
state
的情况下可省略constructor
。 - 构造函数是唯一可以对
this.state
赋值的地方,其他场合仅可使用this.setState()
(类似wx小程序)
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
- 出于性能考虑,React 可能会把多个
setState()
合并成一个,因此setState()
可能是异步的,this.props
和this.state
可能会异步更新,setState()
时不要直接使用他们的值,而是用一个函数作为入参
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
//或
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
自上而下的单向数据流
多重组件嵌套时,通常将父的state
传递给子的props
,任何的 state
总是所属于特定的组件,而且从该 state
派生的任何数据或 UI 只能影响树中“低于”它们的组件。
事件处理
React 事件的命名采用小驼峰式而非纯小写,且在JSX中需传入一个事件处理函数。
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
- 事件的默认参数
e
已做过跨浏览器兼容处理,直接使用e.preventDefault();
即可统一阻止默认事件。
使用class组件时的方法内this指向问题
可类比以下操作
class A {
handleClick1 = () => {
console.log(this, "handleClick1");
}
handleClick2() {
console.log(this, "handleClick2");
}
render() {
window.addEventListener("click", this.handleClick1);//A
window.addEventListener("click", this.handleClick2);//window
}
}
new A().render();
因此有三种方法避免this
指向问题
- 构造函数中使用
bind
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
- 使用
class fields
语法
handleClick = () => {
console.log(this);
}
- 在回调中使用
()=>
或bind
- ()=>
<button onClick={(e) => this.handleClick(id, e)}>Click me</button>
- bind
handleClick(id,event){
...
}
<button onClick={this.handleClick.bind(this, id)}>Click me</button>
条件渲染
当不想进行任何渲染时,可以return null
。
&&
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
?:
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
列表 & Key
列表中的内容是一个React元素的数组,以下两种方式均可生成一个列表
注意列表中必须有key,未指定key时key默认为索引值
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
表单
React中未实现双向绑定
受控组件
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
fruit: "lime"
};
this.handleChange= this.handleChange.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.name === 'isGoing' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleChange} />
<select name="fruit" value={this.state.fruit} onChange={this.handleChange}>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
</form>
);
}
}
非受控组件
- 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性。
- 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.fileInput = React.createRef();
}
handleSubmit(event) {
event.preventDefault();
alert(
`Selected file - ${this.fileInput.current.files[0].name}`
);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(
<FileInput />,
document.getElementById('root')
);
使用 Formik
状态提升
将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,以实现共享 state
实现方式
父元素通过props将待展示的值和该值变化时的回调方法传给子元素。子元素调用该回调时,父元素对应state改变,并重新影响各个子元素。以此实现兄弟元素间的值共享。
打包
在package.json中加入"homepage": "."
,即可使打包后资源路径变为相对路径(否则默认为绝对路径)。
网友评论