props
- 在函數(shù)式組件里面起趾, 使用傳參的形式拿到props
- 在es6 class語法里面, 使用this.props拿到 props
- props是只讀屬性
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ES6 class寫法
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
生命周期
componentDidMount 組件掛載完畢
componentWillUnmount 組件即將卸載
state
constructor(props) {
super(props);
this.state = {date: new Date()}; // 定義一個(gè)state
}
- 注意事項(xiàng):
this.state.comment = 'Hello'; // 此代碼不會(huì)重新渲染組件:
|
| 正確使用方式
| --------------->
this.setState({comment: 'Hello'});
- 注意事項(xiàng)2
this.props為異步獲取數(shù)據(jù)法瑟, this.state也可能是異步獲取數(shù)據(jù), 當(dāng)props或state數(shù)據(jù)改變, 可能會(huì)導(dǎo)致數(shù)據(jù)不會(huì)更新
this.setState({
counter: this.state.counter + this.props.increment,
});
|
| 正確使用方式
| --------------->
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
|
| 或正確使用方式
| --------------->
this.setState(function(prevState, props) {
return {
counter: prevState.counter + props.increment
};
});
事件綁定
- 基礎(chǔ)例子:
<button onClick={activateLasers}>
Activate Lasers
</button>
- 注意事項(xiàng):
- 不能 return false的方式 阻止默認(rèn)行為 必須明確的使用 preventDefault
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
- 綁定this
JSX 回調(diào)函數(shù)中的 this揖闸,類的方法默認(rèn)是不會(huì)綁定 this 的, this 的值會(huì)是 undefined。
解決方法1: 在constructor 中顯示的為 函數(shù) 使用 Bind方法綁定this
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
this.handleClick = this.handleClick.bind(this); // 這里綁定了this
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
);
解決方法2: 函數(shù)使用es6箭頭函數(shù)的方式聲明
handleClick = () => {
console.log('this is:', this);
}
解決方法3:
<button onClick={(e) => this.handleClick(e)}>
Click me
</button>
解決方法4:
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
條件渲染
1.在方法內(nèi)部使用if/else
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
- 在render內(nèi)部使用判斷語句
render() {
const isLoggedIn = this.state.isLoggedIn;
let button = null;
if (isLoggedIn) {
button = <div>我是組件1</div;
} else {
button =<div>我是組件2</div;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
- 使用與運(yùn)算符 &&
function Mailbox(props) {
const unreadMessages = props.unreadMessages;
return (
<div>
<h1>Hello!</h1>
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
</div>
);
}
- 三目運(yùn)算符
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
|
|
| 或這樣
------------->
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn ? (
<LogoutButton onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
)}
</div>
);
}
- 阻止組件渲染
function WarningBanner(props) {
if (!props.warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
map渲染
循環(huán)的時(shí)候記得加key
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>{number}</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
keys 與組件
- 被循環(huán)的根組件內(nèi)添加key
- 數(shù)組元素中使用的key在其兄弟之間應(yīng)該是獨(dú)一無二的料身。然而汤纸,它們不需要是全局唯一的
return (
// 錯(cuò)啦!你不需要在這里指定key:
<li key={value.toString()}>
{value}
</li>
);
const listItems = numbers.map((number) =>
//錯(cuò)啦芹血!元素的key應(yīng)該在這里指定:
<ListItem value={number} />
);
|
|
| 正確使用
|-------》
function ListItem(props) {
// 對(duì)啦贮泞!這里不需要指定key:
return <li>{props.value}</li>;
}
const listItems = numbers.map((number) =>
// 又對(duì)啦!key應(yīng)該在數(shù)組的上下文中被指定
<ListItem key={number.toString()}
value={number} />
);
JSX允許在大括號(hào)中嵌入任何表達(dá)式幔烛,
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
受控組件
- input
- 使用value={this.state.value}綁定數(shù)據(jù)啃擦, 然后通過change事件修改state.value數(shù)據(jù)
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange} />
);
}
}
- textarea
textarea標(biāo)簽的使用方式跟Input一樣, 不同的是饿悬, 在react中令蛉, textarea會(huì)用value屬性來代替
- select
Coconut選項(xiàng)最初由于selected屬性是被選中的。在React中狡恬,并不使用之前的selected屬性珠叔,而在根select標(biāo)簽上用value屬性來表示選中項(xiàng)
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
- input file標(biāo)簽
由于該標(biāo)簽的 value 屬性是只讀的, 所以它是 React 中的一個(gè)非受控組件傲宜。
組件交互(狀態(tài)提升)
//------------------------ 父組件
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
this.state = {temperature: ''};
}
// 注冊(cè)方法
handleCelsiusChange(temperature) {
this.setState({temperature});
}
render() {
const celsius = this.state.temperature;
return (
<div>
<TemperatureInput
// 傳遞參數(shù)值給子組件
temperature={celsius}
// 將方法通過prop傳遞過去
onTemperatureChange={this.handleCelsiusChange} />
</div>
);
}
}
//------------------------ 子組件
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
// 觸發(fā)父組件傳遞過來的參數(shù)的方法运杭, 吧值傳遞回去
handleChange(e) {
this.props.onTemperatureChange(e.target.value);
}
render() {
const temperature = this.props.temperature;
return (
<fieldset>
// 接收到父組件傳遞過來的參數(shù), 并賦值給自己
<input value={temperature}
// 注冊(cè)自己的change事件
onChange={this.handleChange} />
</fieldset>
);
}
}
props.children 子代
通過props.children渲染組件內(nèi)的內(nèi)容
- 渲染內(nèi)部所有內(nèi)容
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>
);
}
- 內(nèi)部?jī)?nèi)容指定渲染位置
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 />
} />
);
}
jsx與react
- react組件與react調(diào)用
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>
|
| 轉(zhuǎn)換
|----->
React.createElement(
MyButton,
{color: 'blue', shadowSize: 2},
'Click Me' // 當(dāng)使用自閉合標(biāo)簽(<div/>) 的時(shí)候函卒, 里面是沒有內(nèi)容的辆憔,可以使用Null放在這里
)
- 點(diǎn)表示法
也可以使用對(duì)象的形式作為組件
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;
}
- 首字母大寫
import React from 'react';
// 正確!組件名應(yīng)該首字母大寫:
function Hello(props) {
// 正確报嵌!div 是有效的 HTML 標(biāo)簽:
return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
// 正確虱咧!React 能夠?qū)⒋髮戦_頭的標(biāo)簽名認(rèn)為是 React 組件。
return <Hello toWhat="World" />;
}
- 組件變量
import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
photo: PhotoStory,
video: VideoStory
};
function Story(props) {
// 正確锚国!JSX 標(biāo)簽名可以為大寫開頭的變量腕巡。
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
//-------------------------------
// 錯(cuò)誤!JSX 標(biāo)簽名不能為一個(gè)表達(dá)式血筑。
return <components[props.storyType] story={props.story} />;
}
- 屬性中的表達(dá)式
你可以傳遞任何 {} 包裹的 JavaScript 表達(dá)式作為一個(gè)屬性值
<MyComponent foo={1 + 2 + 3 + 4} />
if 語句和 for 循環(huán)在 JavaScript 中不是表達(dá)式绘沉,因此它們不能直接在 JSX 中使用煎楣,但是你可以將它們放在周圍的代碼中闹究。
function NumberDescriber(props) {
let description;
if (props.number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}
return <div>{props.number} is an {description} number</div>;
}
- 字符串常量
<MyComponent message="hello world" />
=========
<MyComponent message={'hello world'} />
- 默認(rèn)為 True
<MyTextBox autocomplete />
=======
<MyTextBox autocomplete={true} />
- 擴(kuò)展屬性
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
- 渲染時(shí)铃将, 布爾值, Null, undefined 被忽略, 下面的都等價(jià)
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
propTypes檢測(cè)類型
- 限制類型
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
具體驗(yàn)證例子請(qǐng)打開該鏈接
https://react.docschina.org/docs/typechecking-with-proptypes.html
- 限制單個(gè)子代
import PropTypes from 'prop-types';
class MyComponent extends React.Component {
render() {
// This must be exactly one element or it will warn.
const children = this.props.children;
return (
<div>
{children}
</div>
);
}
}
MyComponent.propTypes = {
children: PropTypes.element.isRequired
};
- 屬性默認(rèn)值
// 為屬性指定默認(rèn)值:
Greeting.defaultProps = {
name: 'Stranger'
};
refs
- 你不能在函數(shù)式組件上使用 ref 屬性
- ref 的更新會(huì)發(fā)生在componentDidMount 或 componentDidUpdate 生命周期鉤子之前
使用 React.createRef() 創(chuàng)建 refs邑遏,通過 ref 屬性來獲得 React 元素
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
- 通過this.myRef.current 拿到dom元素
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
// 創(chuàng)建 ref 存儲(chǔ) textInput DOM 元素
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// 直接使用原生 API 使 text 輸入框獲得焦點(diǎn)
// 注意:通過 "current" 取得 DOM 節(jié)點(diǎn)
this.textInput.current.focus();
}
render() {
// 告訴 React 我們想把 <input> ref 關(guān)聯(lián)到構(gòu)造器里創(chuàng)建的 `textInput` 上
return (
<div>
<input
type="text"
ref={this.textInput} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
- 回調(diào) Refs
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.textInput = null;
// 這里的回調(diào) 把當(dāng)前元素賦值給this.textInput
this.setTextInputRef = element => {
this.textInput = element;
};
this.focusTextInput = () => {
// 直接使用原生 API 使 text 輸入框獲得焦點(diǎn)
if (this.textInput) this.textInput.focus();
};
}
componentDidMount() {
// 渲染后文本框自動(dòng)獲得焦點(diǎn)
this.focusTextInput();
}
render() {
// 使用 `ref` 的回調(diào)將 text 輸入框的 DOM 節(jié)點(diǎn)存儲(chǔ)到 React
// 實(shí)例上(比如 this.textInput)
return (
<div>
<input
type="text"
ref={this.setTextInputRef}
/>
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
非受控組件
- 基礎(chǔ)用法
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
// 這里拿到DOM元素
<input type="text" ref={(input) => this.input = input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
- 默認(rèn)值 defaultValue
你希望 React 可以為其指定初始值另玖,但不再控制后續(xù)更新困曙。 你可以指定一個(gè) defaultValue 屬性而不是 value
同樣,<input type="checkbox"> 和 <input type="radio"> 支持 defaultChecked谦去,<select> 和 <textarea> 支持 defaultValue.
<input
defaultValue="Bob"
type="text"
ref={(input) => this.input = input} />
Context
Context 可以用來跨子組件給更下級(jí)的組件傳參
- 創(chuàng)建一個(gè)Context
- Provider 作為傳遞組件的根組件
- Consumer 作為Provider 下的接收參數(shù)的組件Consumer
const {Provider, Consumer} = React.createContext(defaultValue);
- 接收一個(gè) value 屬性傳遞給 Provider 的后代 Consumers慷丽。一個(gè) Provider 可以聯(lián)系到多個(gè) Consumers。
<Provider value={/* some value */}>
- Consumer
<Consumer>
// 這里接收一個(gè)函數(shù)鳄哭, 傳遞值為 Provider的value
{value => /* render something based on the context value */}
</Consumer>
示例
export const themes = {
light: {
foreground: '#ffffff',
background: '#222222',
},
dark: {
foreground: '#000000',
background: '#eeeeee',
},
};
export const ThemeContext = React.createContext(
themes.dark // 默認(rèn)值
);
import {ThemeContext} from './theme-context';
function ThemedButton(props) {
return (
// 定義 Consumer
<ThemeContext.Consumer>
{theme => (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
)}
</ThemeContext.Consumer>
);
}
export default ThemedButton;
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
this.toggleTheme = () => {
this.setState(state => ({
theme:
state.theme === themes.dark
? themes.light
: themes.dark,
}));
};
}
render() {
return (
<Page>
// 定義 Provider
<ThemeContext.Provider value={this.state.theme}>
<ThemedButton onClick={this.toggleTheme} /> // 點(diǎn)擊切換Provider.value
</ThemeContext.Provider>
</Page>
);
}
}
ReactDOM.render(<App />, document.root);
Fragments 空的 JSX 標(biāo)簽:
- 作用: 當(dāng)渲染td的時(shí)候要糊, 需要一個(gè)根組件, 但卻不能隨便使用窃诉, 因此可以使用一個(gè)空標(biāo)簽代替杨耙;
class Columns extends React.Component {
render() {
return (
<div>
<td>Hello</td>
<td>World</td>
</div>
);
}
}
|
|
| 輸出結(jié)果
|- -------->
<table>
<tr>
<div> // 這里多了div
<td>Hello</td>
<td>World</td>
</div>
</tr>
</table>
- <React.Fragment> 與<>
<React.Fragment> == <>
- Fragment的屬性
- key 是唯一可以傳遞給 Fragment 的屬性
<React.Fragment key={item.id}></React.Fragment>