我有一个使用Accordion
,AccordionItem
和Link
的问答题。
除了Link
以外,其他所有东西都运行良好,当在小提琴中的手风琴组件行50之外时,它可以完美呈现,但是当它嵌套在小提琴中的sampleQuestions > question1 > answer
,第59行中时,则无法正常工作。
它将答案呈现为:
Ottawa baby!! Check [object Object] for more details.
代替所需的链接:Ottawa baby!! Check wikipedia link b for more details.
这里是参考代码,但是我建议直接跳到代码下面的小提琴,单击第一个问题,然后第一手看到问题。
class Link extends React.Component {
render() {
return (
<span onClick={this.props.onClick} className="link">{this.props.linkTitle}</span>
);
}
}
class AccordionItem extends React.Component {
constructor() {
super();
this.state = {
active: false
};
this.toggle = this.toggle.bind(this);
}
toggle() {
this.setState({
active: !this.state.active,
className: "active"
});
}
render() {
const activeClass = this.state.active ? "active" : "inactive";
const question = this.props.details;
return (
<div className={activeClass} onClick={this.toggle}>
<span className="summary">{question.summary}</span>
<span className="folding-pannel answer">{question.answer}</span>
</div>
);
}
}
class Accordion extends React.Component {
constructor() {
super();
this.state = {
questions: sampleQuestions,
};
this.renderQuestion = this.renderQuestion.bind(this);
}
renderQuestion(key) {
return <AccordionItem key={key} index={key} details={this.state.questions[key]} />
}
render() {
return(
<div className="mainbody">
<h1>What is...</h1>
<Link onClick={() => alert('outside link works')} linkTitle={'wikipedia link a'} />
<div className="accordion-container">
{Object.keys(this.state.questions).map(this.renderQuestion)}
</div>
</div>
)
}
}
const sampleQuestions = {
question1: {summary:'the capital of Canada?', answer:'Ottawa baby!! Check ' + <Link onClick={() => alert('trying to get this nested link to show')} linkTitle={'wikipedia link b'} /> + ' for more details.'},
question2: {summary:'the life span of a bowhead whale?', answer:'Over 200 years!!'},
question3: {summary:'the most visited city in the world?', answer:'London, groovy baby!!'},
question4: {summary:'the warmest ocean?', answer:'Indian Ocean, it\'s a hottie!'},
question5: {summary:'the one thing ron swanson hates more than lying?', answer:'Skim milk, which is water that\'s lying about being milk'}
};
ReactDOM.render(
<Accordion />,
document.getElementById('accordion')
);
是否知道如何获取[object Object]
来呈现第一个问题的答案所需的Link
分量?
答案 0 :(得分:1)
工作示例:https://codesandbox.io/s/92r12m7zp
public / index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<pattern id="pattern" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
<rect fill="rgba(159, 188, 191, 0.15)" x="0" width="20" height="20" y="0" />
<rect fill="rgba(159, 188, 191, 0.15)" x="20" width="20" height="20" y="20" />
</pattern>
<rect fill="url(#pattern)" x="0" y="0" width="100%" height="100%" />
</svg>
<div id="accordion"></div>
</body>
</html>
index.js
import React from "react";
import { render } from "react-dom";
import Accordian from "./Accordian";
import "./styles.css";
render(<Accordian />, document.getElementById("accordion"));
Accordian.js
import map from "lodash/map";
import React, { Component } from "react";
import AccordionItem from "./AccordianItem";
import SampleQuestions from "./sampleQuestions";
export default class Accordion extends Component {
state = { questions: SampleQuestions };
render = () => (
<div className="mainbody">
<h1>What is...</h1>
<div className="accordion-container">
{map(this.state.questions, ({ key, ...rest }) => (
<AccordionItem key={key} {...rest} />
))}
</div>
</div>
);
}
AccordianItem.js
import React, { Component } from "react";
export default class AccordionItem extends Component {
state = { isActive: false };
toggle = () => this.setState(prevState => ({ isActive: !this.state.isActive }));
render = () => (
<div
className={`${this.state.isActive ? "active" : "inactive"}`}
onClick={this.toggle}
>
<span className="summary">> {this.props.summary}</span>
<span className="folding-pannel answer">
{this.props.answer}
</span>
</div>
);
}
sampleQuestions.js
import React, { Fragment } from "react";
const Link = url => (
<a href={url} target="_blank">
here
</a>
);
export default [
{
key: "capital-of-canada",
summary: "the capital of Canada?",
answer: (
<Fragment>
Ottawa baby!! Click {Link("https://en.wikipedia.org/wiki/Ottawa")} for
more details
</Fragment>
)
},
{
key: "whale-lifespan",
summary: "the life span of a bowhead whale?",
answer: "Over 200 years!!"
},
{
key: "most-popular-city",
summary: "the most visited city in the world?",
answer: "London, groovy baby!!"
},
{
key: "warmest-ocean",
summary: "the warmest ocean?",
answer: "Indian Ocean, it's a hottie!"
},
{
key: "swanson",
summary: "the one thing ron swanson hates more than lying?",
answer: "Skim milk, which is water that's lying about being milk"
}
];
工作示例:https://codesandbox.io/s/1v1xmq1kmq
public / index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<pattern id="pattern" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
<rect fill="rgba(159, 188, 191, 0.15)" x="0" width="20" height="20" y="0" />
<rect fill="rgba(159, 188, 191, 0.15)" x="20" width="20" height="20" y="20" />
</pattern>
<rect fill="url(#pattern)" x="0" y="0" width="100%" height="100%" />
</svg>
<div id="accordion"></div>
</body>
</html>
index.js
import React from "react";
import { render } from "react-dom";
import Accordian from "./Accordian";
import "./styles.css";
render(<Accordian />, document.getElementById("accordion"));
Accordian.js
import map from "lodash/map";
import React, { Component } from "react";
import AccordionItem from "./AccordianItem";
import SampleQuestions from "./sampleQuestions";
export default class Accordion extends Component {
state = { questions: SampleQuestions };
render = () => (
<div className="mainbody">
<h1>What is...</h1>
<div className="accordion-container">
{map(this.state.questions, ({ key, ...rest }) => (
<AccordionItem key={key} {...rest} />
))}
</div>
</div>
);
}
AccordianItem.js
import each from "lodash/each";
import React, { Component, Fragment } from "react";
import uuid from "uuid/v5";
export default class AccordionItem extends Component {
state = { isActive: false };
toggle = () => this.setState(prevState => ({ isActive: !this.state.isActive }));
render = () => (
<div
className={`${this.state.isActive ? "active" : "inactive"}`}
onClick={this.toggle}
>
<span className="summary">> {this.props.summary}</span>
<span className="folding-pannel answer">
{each(this.props.answer, prop => <Fragment key={uuid}>{prop}</Fragment>)}
</span>
</div>
);
}
sampleQuestions.js
import React from "react";
const Link = url => (
<a href={url} target="_blank">
here
</a>
);
export default [
{
key: "capital-of-canada",
summary: "the capital of Canada?",
answer: [
"Ottawa baby!! Click ",
Link("https://en.wikipedia.org/wiki/Ottawa"),
" for more details"
]
},
{
key: "whale-lifespan",
summary: "the life span of a bowhead whale?",
answer: ["Over 200 years!!"]
},
{
key: "most-popular-city",
summary: "the most visited city in the world?",
answer: ["London, groovy baby!!"]
},
{
key: "warmest-ocean",
summary: "the warmest ocean?",
answer: ["Indian Ocean, it's a hottie!"]
},
{
key: "swanson",
summary: "the one thing ron swanson hates more than lying?",
answer: ["Skim milk, which is water that's lying about being milk"]
}
];
工作示例:https://codesandbox.io/s/0q1mv0omkw
public / index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<pattern id="pattern" x="0" y="0" width="24" height="24" patternUnits="userSpaceOnUse">
<rect fill="rgba(159, 188, 191, 0.15)" x="0" width="20" height="20" y="0" />
<rect fill="rgba(159, 188, 191, 0.15)" x="20" width="20" height="20" y="20" />
</pattern>
<rect fill="url(#pattern)" x="0" y="0" width="100%" height="100%" />
</svg>
<div id="accordion"></div>
</body>
</html>
index.js
import React from "react";
import { render } from "react-dom";
import Accordian from "./Accordian";
import "./styles.css";
render(<Accordian />, document.getElementById("accordion"));
Accordian.js
import map from "lodash/map";
import React, { Component } from "react";
import AccordionItem from "./AccordianItem";
import SampleQuestions from "./sampleQuestions";
export default class Accordion extends Component {
state = { questions: SampleQuestions };
render = () => (
<div className="mainbody">
<h1>What is...</h1>
<div className="accordion-container">
{map(this.state.questions, ({ key, ...rest }) => (
<AccordionItem key={key} {...rest} />
))}
</div>
</div>
);
}
AccordianItem.js
import React, { Component } from "react";
import sanitizeHtml from "sanitize-html";
export default class AccordionItem extends Component {
state = { isActive: false };
toggle = () => this.setState(prevState => ({ isActive: !this.state.isActive }));
sanitize = ans =>
sanitizeHtml(ans, {
allowedTags: ["a"],
allowedAttributes: {
a: ["href", "target"]
}
});
render = () => (
<div
className={`${this.state.isActive ? "active" : "inactive"}`}
onClick={this.toggle}
>
<span className="summary">> {this.props.summary}</span>
<span
className="folding-pannel answer"
dangerouslySetInnerHTML={{
__html: this.sanitize(this.props.answer)
}}
/>
</div>
);
}
sampleQuestions.js
const Link = url => `<a href=${url} target="_blank">here</a>`;
export default [
{
key: "capital-of-canada",
summary: "the capital of Canada?",
answer: `Ottawa baby!! Click ${Link("https://en.wikipedia.org/wiki/Ottawa")} for more details`
},
{
key: "whale-lifespan",
summary: "the life span of a bowhead whale?",
answer: "Over 200 years!!"
},
{
key: "most-popular-city",
summary: "the most visited city in the world?",
answer: "London, groovy baby!!"
},
{
key: "warmest-ocean",
summary: "the warmest ocean?",
answer: "Indian Ocean, it's a hottie!"
},
{
key: "swanson",
summary: "the one thing ron swanson hates more than lying?",
answer: "Skim milk, which is water that's lying about being milk"
}
];
答案 1 :(得分:1)
感谢所有回答的人,但是我发现这样做的方式不太麻烦。正如patrick在评论中所建议的那样,只需将答案包装在div中即可将答案转换为jsx而不是字符串。
这是现在的样子:
answer: <div>Ottawa baby!! Check <Link onClick={() => alert('trying to get this nested link to show')} linkTitle={'wikipedia link b'} /> for more details.</div>
这是最简单的解决方案,并且可以按预期获取要呈现的链接。
答案 2 :(得分:0)
通常,您不能真正将react组件放在字符串中。有多种方法可以做到这一点,即使用react-jsx-parser
,但我们将不再赘述。
一种可能的解决方案是执行以下操作:设置一个哑子组件,该子组件呈现子级数组。
const AnswerWithLink = (children) => {
return (
<span>{[...children]}</span>
)
}
然后在答案1中,将其作为函数调用,并将字符串的各个部分作为数组的元素传递:
question1: {
summary:'the capital of Canada?',
answer: AnswerWithLink(['Ottawa baby!! Check ', Link({onClick: () => alert('trying to get this nested link to show'), linkTitle: 'wikipedia link b'}), ' for more details'])
}
我敢肯定,这样做有更有效的方法。
编辑:我还编辑了代码笔以使其正常工作。最终也将<Link />
更改为愚蠢的组件,因为它是无状态的。