先从 react 最基本的条件类型来看。如果有数据就显示组件,如果没有数据就不显示任何内容。posts 为需要渲染的列表:
export default function App() {
const { posts } = usePosts();
if (!posts) return null;
return (
<div>
<PostList posts={posts} />
</div>
);
}
这种形式会生效的原因就是我们会提前返回,如果满足条件(posts 值不存在),就通过return null 在组件中不显示任何内容。
如果有多个要检查的条件时,也可以使用 if 语句。例如,在显示数据之前检查加载和错误状态:
export default function App() {
const { isLoading, isError, posts } = usePosts();
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error!</div>;
return (
<div>
<PostList posts={posts} />
</div>
);
}
这里我们可以多次使用 if 语句,不需要再使用 else 或者 if-eles 语句,这样就减少了需要编写的代码,并且可读性更强。
当我们想提前退出或者什么都不显示时,if 语句会很有用。但是,如果我们不想写一个与返回的 JSX 分开的条件,而是直接在其中写呢?那就可以使用三元表达式来编写条件。
在 React 中,我们必须在 JSX 中包含表达式,而不是语句。这就是为什么我们在 JSX 中只能使用三元表达式,而不是 if 语句来编写条件。
例如,在移动设备的屏幕上显示一个组件,而在更大的屏幕上显示另一个组件,就可以使用三元表达式来实现:
export default function App() {
const isMobile = useWindowSize()
return (
<main>
<Header />
{isMobile ? <MobileChat /> : <Chat />}
</main>
)
}
其实,不必将这些三元表达式包含在 JSX 中,可以将其结果分配给一个变量,然后在需要的地方使用即可:
export default function App() {
const isMobile = useWindowSize();
const ChatComponent = isMobile ? <MobileChat /> : <Chat />;
return (
<main>
<Header />
<Sidebar />
{ChatComponent}
</main>
)
}
在许多情况下,我们可能想要使用三元表达式,但是如果不满足条件,就不显示任何内容。那代码会是这样的:
condition ? <Component /> : null.
可以使用 && 运算符来简化:
export default function App() {
const { posts, hasFinished } = usePosts()
return (
<>
<PostList posts={posts} />
{hasFinished && (
<p>已经到底啦!</p>
)}
</>
)
}
如果条件为真,则逻辑 && 运算符之后的表达式将是输出。如果条件为假,React 会忽略并跳过表达式.
过多的 if 语句会导致组件变得混乱,可以将多个条件提取到包含 switch 语句的单独的组件中(根据组件逻辑的复杂程度来选择是否提取到单独的组件)。下面来看一个简单的菜单切换组件:
export default function Menu() {
const [menu, setMenu] = React.useState(1);
const toggleMenu = () => {
setMenu((m) => {
if (m === 3) return 1;
return m + 1;
});
}
return (
<>
<MenuItem menu={menu} />
<button onClick={toggleMenu}>切换菜单</button>
</>
);
}
function MenuItem({ menu }) {
switch (menu) {
case 1:
return <Users />;
case 2:
return <Chats />;
case 3:
return <Rooms />;
default:
return null;
}
}
由于使用带有 switch 语句的 MenuItem 组件父菜单组件不会被条件逻辑弄乱,可以很容易地看到给定 menu 状态将显示哪个组件。需要注意,必须为 switch case 运算符使用默认值,因为在 React 中,组件始终需要返回一个元素或 null。
在 JavaScript 中,当对象用作键值对的映射时,它可以用作枚举:
const ENUMOBJECT = {
a: '1',
b: '2',
c: '3',
};
假如要创建三个不同的组件 Foo、Bar 和 Default,并根据某种状态显示这些组件:
const Foo = () => {
return <button>FOO</button>;
};
const Bar = () => {
return <button>BAR</button>;
};
const Default = () => {
return <button>DEFAULT</button>;
};
创建可用作枚举的对象:
const ENUM_STATES = {
foo: <Foo />,
bar: <Bar />,
default: <Default />
};
渲染这个枚举对象的函数:
function EnumState({ state }) {
return <div>{ENUM_STATES[state]}</div>;
}
上面的 state 属性可以从对象中检索值。可以看到,与 switch case 运算符相比,它更具可读性。
JSX Control Statements 库扩展了 JSX 的功能,从而可以直接使用 JSX 实现条件渲染。它是一个 babel 插件,可以在转译过程中将类似组件的控制语句转换为对应的 JavaScript。
安装babel-plugin-jsx-control-statements包并修改 Babel 配置后,可以像这样重写应用程序:
export default function App(props) {
const [isLoggedIn, setIsLoggedIn] = useState(false);
//...
return (
<Choose>
<When condition={isLoggedIn}>
<button>Logout</button>;
</When>
<When condition={!isLoggedIn}>
<button>Login</button>;
</When>
</Choose>
);
}
当然,不建议这样来编写条件语句,这样会导致代码的可读性变差,并且 JSX 允许使用强大的 JavaScript 功能来自己处理条件渲染,无需添加模板组件即可启用它。
高阶组件 (HOC)与 React 中的条件渲染完美匹配。HOC 可以帮助处理多个用例,但一个用例可能是使用条件渲染来改变组件的外观。让我们看看显示元素或组件的 HOC:
function withLoadingIndicator(Component) {
return function EnhancedComponent({ isLoading, ...props }) {
if (!isLoading) {
return <Component {...props} />;
}
return (
<div>
<p>Loading</p>
</div>
);
};
}
const ListWithLoadingIndicator = withLoadingIndicator(List);
function App({ list, isLoading }) {
return (
<ListWithLoadingIndicator isLoading={isLoading} list={list} />
);
}
在这个例子中,List 组件可以专注于呈现列表。而不必再加载状态。HOC 隐藏了实际组件中的所有干扰。最终,可以添加多个高阶组件来隐藏多个条件渲染边缘情况。
来看一个常见的渲染示例,当数组中存在元素时才渲染内容:
{gallery.length && <Gallery slides={gallery}>}
预想的结果是,数组存在元素时渲染内容,不存在元素时什么都不渲染。但是,页面上得到了 “0”。这是因为在使用与运算符时,一个假的左侧值(如 0)会立即返回。在JavaScript中,布尔运算法不会将其结果转化为布尔值。所以,React 将得到的值放入dom中,与 false 不同的是,0 是一个有效的 React 节点,所以最终会渲染成0。
那该如何避免这个问题呢?可以显式的将条件转换为布尔值,当表达式结果为false时,就不会在页面中渲染了:
gallery.length > 0 && jsx
!!gallery.length && jsx
Boolean(gallery.length) && jsx
或者使用三元表达式来实现:
{gallery.length ? <Gallery slides={gallery} /> : null}
与运算符(&&)比或运算符(||)具有更高的优先级。所以,要格外小心使用包含与运算符的 JSX 条件:
user.anonymous || user.restricted && <div className="error" />
这样写就相当于:
user.anonymous || (user.restricted && <div className="error" />)
这样,与运算符左侧为真时就会直接返回,而不会继续执行后面的代码。所以,多数情况下,看到或运算符时,就将其使用括号括起来,避免因为优先级问题而渲染出错:
{(user.anonymous || user.restricted) && <div className="error" />}
三元表达式适合在两个JSX之间进行切换,一旦超过两个项目,代码就会变得糟糕:
{
isEmoji
? <EmojiButton />
: isCoupon
? <CouponButton />
: isLoaded && <ShareButton />
}
有时使用 && 来实现会更好,不过一些条件判断会重复:
{isEmoji && <EmojiButton />}
{isCoupon && <CouponButton />}
{!isEmoji && !isCoupon && isLoaded && <ShareButton />}
当然,这种情况下,使用 if 语句可能是更好的选择:
const getButton = () => {
if (isEmoji) return <EmojiButton />;
if (isCoupon) return <CouponButton />;
return isLoaded ? <ShareButton /> : null;
};
通过 props 传递的 React 元素能不能作为判断条件呢?来看一个简单的例子:
const Wrap = (props) => {
if (!props.children) return null;
return <div>{props.children}</div>
};
我们希望 Wrap 在没有包含内容时呈现 null,但 React 不是这样工作的:
因此,不要将JSX作为判断条件,避免出现一些难以预料的问题。
用三元表达式编写的 JSX 感觉就像是完全独立的代码:
{hasItem ? <Item id={1} /> : <Item id={2} />}
当 hasItem 改变时会发生什么?我的猜测是 <Item id={1} /> 卸载,然后 <Item id={2} /> 安装,因为这里写了 2 个单独的 JSX 标签。然而,React 并不知道也不关心我们写了什么,它所看到的只是 Item 元素在同一个位置,所以它保持挂载的实例,更新 props。上面的代码等价于 <Item id={hasItem ? 1:2} /> 。
注意:如果三元表达式包含的是不同的组件,如 {hasItem ? <Item1 /> : <Item2 />} ,hasItem改变时,React 会重新挂载,因为 Item1 无法更新为 Item2。
上述情况会导致一些意外的行为:
{
mode === 'name'
? <input placeholder="name" />
: <input placeholder="phone" />
}
这里,如果在 name 的 input 中输入了一些内容,然后切换模式(mode),在 name 中输入内容的就会泄漏到 phone 的 input 中,这可能会对依赖于先前状态的复杂更新机制造成更大的破坏。
这里的一种解决方法是使用 key。通常,我们用它来渲染列表,但它实际上是 React 的元素标识提示——具有相同 key 的元素是相同的逻辑元素:
{
mode === 'name'
? <input placeholder="name" key="name" />
: <input placeholder="phone" key="phone" />
}
另一种方法是用两个单独的 && 块来替换三元表达式。当 key 不存在时,React 会回退到子数组中项目的索引,因此将不同的元素放在不同的位置与显式定义 key 的效果是一样的:
{mode === 'name' && <input placeholder="name" />}
{mode !== 'name' && <input placeholder="phone" />}
参考:
https://blog.thoughtspile.tech/2022/01/17/jsx-conditionals/。
https://ordinarycoders.com/blog/article/react-conditional-rendering。
来源: 前端充电宝
在使用vue的时候,我们都知道它是双向数据绑定的,但是在使用不熟的情况下,经常会遇到:data中的数据变化了,但是并没有触发页面渲染。下面就整理一些出现这种情况的场景以及解决办法。
这里结合art-template模板引擎说明。首先了解下前端页面中如何使用art-template。当不需要对SEO友好的时候,推荐使用客户端渲染;当需要对 SEO友好的时候,推荐使用服务器端渲染
在使用vue的时候,偶然发现多次刷新或者网络加载缓慢的时候,会一瞬间出现设置的模板的情况。实在很影响美观,可以使用vue现成的指令来解决这个问题:v-cloak
大部分Web应用的富文本内容都是以HTML字符串的形式存储的,通过HTML文档去展示HTML内容自然没有问题。但是,在微信小程序(下文简称为「小程序」)中,应当如何渲染这部分内容呢?
估计大家都听过,尽量将 CSS 放头部,JS 放底部,这样可以提高页面的性能。然而,为什么呢?大家有考虑过么?很长一段时间,我都是知其然而不知其所以然,强行背下来应付考核当然可以,但实际应用中必然一塌糊涂
原生JS改变页面数据,必须要获取页面节点,也即是进行DOM操作,jQuery之类的框架只是简化DOM操作的写法,实质并没有改变操作页面数据的底层原理,DOM操作影响性能(导致浏览器的重绘和回流),Vue是一个mvvm框架(库),大幅度减少了DOM操作
在决定渲染方式时,需要测量和理解真正的瓶颈在哪里。静态渲染或服务器渲染在多数情况都比较适用,尤其是可交互性对JS依赖较低的场景。下面是一张便捷的信息图,显示了服务器到客户端的技术频谱:
如果从服务端返回的数据量较少,或者只有几个字段,可以用vue的set方法,如果数据量较大,请直接看第二种情况。官网API是这样介绍的:Vue.set(target,key,value)
当数据需要异步加载时render获取不到数据可能会报一些错误,此时需要在render函数中加一个判断.行到render时,state对象的haveData为false, 所以此时页面展示 loading,当异步获取数据成功时
在vue.js中,要将一段字符串渲染成html,可以使用v-html指令。但是 官方文档 中的v-html部分也提醒了
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!