Context
使用場景
- 為了解決props的繁瑣傳遞問題家夺,Context提供一種組件間共享值的方式鞭缭,不必顯示通過組件數(shù)逐層傳遞props;
- 很多不同層級的組件需要訪問同樣一些的數(shù)據(jù)躺盛,例如獲取當前認證的用戶把沼、主題或首選語言古戴,類似于全局緩存劲赠;
- Context有時候可由組件組合(component composition鼠证,即把組件當做props傳遞)代替峡竣。
使用步驟
創(chuàng)建context:
const ThemeContext = React.createContext({theme: 'light', text: '按鈕'});
ThemedButton.contextType = ThemeContext;賦值context:
<ThemeContext.Provider value={{theme: 'primary', text: '提交'}}>
這里的value值可以傳字符串,數(shù)字或者對象量九;
如要更新context适掰,可以通過更新state再把state傳入context的方式實現(xiàn)。渲染context:
static contextType = ThemeContext;
// React 會往上找到最近的 theme Provider荠列,然后使用它的值类浪。
return <div className={'btn '+this.props.theme}>{this.props.value}</div>
或
<ThemeContext.Consumer>
{
context => (
<div className={'btn '+this.context.theme}>{this.context.text}</div>
)
}
</ThemeContext.Consumer>-
context嵌套:
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>// 一個組件可能會消費多個 context
function Content() {
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
Refs轉(zhuǎn)發(fā)
使用場景
- 需要將 ref 自動地通過組件傳遞到其一子組件;
- 父組件通過React.createRef()生成傳入肌似,子組件通過React.forwardRef((props, ref) => ())接收渲染费就。
Fragments
- 一個組件返回多個元素。Fragments 允許你將子列表分組川队,而無需向 DOM 添加額外節(jié)點力细,
如return (
<React.Fragment>
<ChildA />
<ChildB />
<ChildC />
</React.Fragment>
); - 循環(huán)時key可以加在React.Fragment節(jié)點標簽上。
高階組件(HOC)
高階組件是參數(shù)為組件固额,返回值為新組件的函數(shù)眠蚂。
-
使用方法:
class ShowUserPermit extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>showUserPermit... {this.props.VIP}</div>
)
}
}
class ShowUserVipInfo extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>showUserVipInfo... {this.props.VIP}</div>
)
}
}function wrap(WrappedComponent) {
return class reComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
VIP: 1000
}
}
render() {
return <WrappedComponent VIP={this.state.VIP}/>
}
}
}const id = document.getElementById('example');
const OtherShowUserVipInfo = wrap(ShowUserVipInfo);
const OtherShowUserPermit = wrap(ShowUserVipInfo);
const ele = <React.Fragment>
<OtherShowUserVipInfo />
<OtherShowUserPermit />
</React.Fragment>
ReactDOM.render(ele, id); HOC 不會修改傳入的組件,也不會使用繼承來復(fù)制其行為对雪。相反河狐,HOC 通過將組件包裝在容器組件中來組成新組件。HOC 是純函數(shù)瑟捣,沒有副作用馋艺;
不要在 render 方法中使用 HOC;
深入JSX
-
在 JSX 類型中使用點語法:
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;
} 用戶定義的組件必須以大寫字母開頭;
在運行時選擇類型:
function Story(props) {
// 錯誤!JSX 類型不能是一個表達式迈套。
return <components[props.storyType] story={props.story} />;
}
function Story(props) {
// 正確捐祠!JSX 類型可以是大寫字母開頭的變量。
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}JavaScript 表達式可作為 Props桑李,如<MyComponent foo={1 + 2 + 3 + 4} />;
if 語句以及 for 循環(huán)不是 JavaScript 表達式踱蛀,所以不能在 JSX 中直接使用窿给,但是可以在JSX之外用;
Props 默認值為 True
props展開:
const props = {firstName: 'Ben', lastName: 'Hector'};
<Hello {...props}/> 與 <Hello firstName={props.firstName} lastName={props.lastName} />等價如果你想渲染 false、true率拒、null崩泡、undefined 等值,你需要先將它們轉(zhuǎn)換為字符串:
<div>My JavaScript variable is {String(myVariable)}.</div>
Portals
ReactDOM.createPortal(child, container)
- Portal 提供了一種將子節(jié)點渲染到存在于父組件以外的 DOM 節(jié)點的優(yōu)秀的方案;
- 第一個參數(shù)(child)是任何可渲染的 React 子元素猬膨,例如一個元素角撞,字符串或 fragment。第二個參數(shù)(container)是一個 DOM 元素勃痴。
Render Props
- 在 React 組件之間使用一個值為函數(shù)的 prop 共享代碼的簡單技術(shù);
- 具有 render prop 的組件接受一個返回 React 元素的函數(shù)谒所,并在組件內(nèi)部通過調(diào)用此函數(shù)來實現(xiàn)自己的渲染邏輯:
<DataProvider render={data => (<h1>{data.target}</h1>)}/> - 本質(zhì)上是把一個回調(diào)函數(shù)傳入到組件里,通過回調(diào)函數(shù)的參數(shù)data再次渲染指定組件沛申;
- 任何被用于告知組件需要渲染什么內(nèi)容的函數(shù) prop 在技術(shù)上都可以被稱為 “render prop”劣领,不一定非要起 render 名稱;
- 實例代碼如下:
// 以下組件跟蹤 Web 應(yīng)用程序中的鼠標位置
class Man extends React.Component {
constructor(props) {
super(props);
}
render() {
const mouse = this.props.mouse;
return <p>人散步:當前的人的位置是 ({mouse.x}, {mouse.y})</p>
}
}
class Cat extends React.Component {
constructor(props) {
super(props);
}
render() {
const mouse = this.props.mouse;
return <p>貓追老鼠:當前的貓的位置是 ({mouse.x}, {mouse.y})</p>
}
}
class Mouse extends React.Component {
constructor (props) {
super(props);
this.state = {
x: 0,
y: 0
};
this.handleMouseMove = this.handleMouseMove.bind(this);
}
handleMouseMove(event) {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{height: '10vh'}} onMouseMove={this.handleMouseMove}>
{ /<Cat mouse={this.state}/>/ }
{
/*
使用render
prop 動態(tài)決定要渲染的內(nèi)容,
而不是給出一個 <Mouse> 渲染結(jié)果的靜態(tài)表示
b
*/
}
{
this.props.render(this.state,this.props.type)
}
</div>
)
}
}
class MouseTracker extends React.Component {
constructor(props) {
super(props);
this.renderMouse = this.renderMouse.bind(this);
}
renderMouse(mouse,Type) {
return <Type mouse={mouse}/>
}
render() {
return (
<div>
<h1>移動鼠標!</h1>
<Mouse type={Cat} render={this.renderMouse}/>
<Mouse type={Man} render={this.renderMouse}/>
</div>
)
}
}
const id = document.getElementById('example');
const ele = <React.Fragment>
<MouseTracker />
</React.Fragment>;
ReactDOM.render(ele, id);