検索条件
お知らせ
現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
- まず
history.push('/path/to/dest')
自体のテストを書くことはないはずなので、何かしらの副作用として実行される事が前提です
- testing-library.com に書いてあることの応用です
/**
* useHistory() を使えるようにするテストユーティリティ
*/
const renderWithRouter = (children: JSX.Element, { route = '/' } = {}) => {
window.history.pushState({}, 'Test page', route);
return render(children, {
wrapper: BrowserRouter,
});
};
// spy 用のモック関数
const mockPush = jest.fn();
// react-router-dom をモックにする
jest.mock('react-router-dom', () => ({
useHistory: () => ({
// モック関数を設定
push: mockPush,
}),
}));
describe('Bar', () => {
it('history.push のテスト', () => {
renderWithRouter(<Bar />, {
route: '/foo/bar',
});
// ここらへんに同期的に副作用を起こす処理を書く
// 以降、副作用で history.push('/foo/baz') されたとする
// 呼ばれたことの確認
expect(mockPush).toBeCalled();
// 引数の確認
expect(mockPush.mock.calls[0][0]).toBe('/foo/baz');
});
});
const onSubmit = (ev: React.FormEvent<HTMLFormElement>) => {
ev.preventDefault();
const target = ev.target as typeof ev.target & {
t1: { value: string };
t2: { value: string };
};
console.log(target.t1.value);
console.log(target.t2.value);
};
return (
<div className="App">
<form onSubmit={(ev) => onSubmit(ev)}>
<input type="text" id="t1" />
<input type="text" id="t2" />
<input type="submit" />
</form>
</div>
);
ReactでSPAを組んでいてブラウザバックしたときのフォームの入力内容が消し飛んで気になったので、ブラウザバックした時にどうなるのかというのを軽く調査した結果
確認したパターンとしては次の2つ
- フォームの入力値をDOMに保持させるステートレスな方式
- フォームの入力値をJSに保持させるステートフルな方式
LocalStorageに画面情報を保存して復元するとか、条件分岐を使ってDOMを隠して保持させるとか、そういう系は考慮しない
|
DOM 保持 |
JS 保持 |
SPA 内ブラウザバック |
消える |
保持される |
SPA 外ブラウザバック |
保持される |
消える |
コード記述量 |
少ない |
多い |
この方式だとhistory.push()
でDOMが消し飛ぶのでSPA内でのブラウザバックで入力したデータが保持されません
その代わりSPAの外、別のサイトに遷移してからブラウザバックしたときは、DOMが残っているので入力したデータが保持されます
この方式だとJSでステート管理をしているため、history.push()
で遷移してDOMが消し飛んでも、 defaultValue
に持ってる値を突っ込んであげれば、取り敢えず入力したデータを保持することが出来ます
反対にSPAの外、別のサイトに遷移してからブラウザバックしたときは、メモリの中身が飛んでるので入力したデータが保持されません
ちゃちゃっと書いたのでコードは超雑です
Env |
Ver |
react |
17.0.2 |
react-dom |
17.0.2 |
react-router-dom |
5.2.0 |
大正義ステートレスです
Function Componentはステートレスなので、こうあってほしいですよね~
コードもシンプルで管理しやすいのが素敵なところです
export const StatelessPage = () => {
const history = useHistory();
return (
<div>
<form>
<input type="text" />
<button onClick={() => history.push(AppRoute.dom2.path)}>submit</button>
</form>
</div>
);
};
ギルティなステートフル方式です
Class Componentを捨てたはずなのにどうしてこうなった…
コードが煩雑で管理が大変です
export const StatefullPage = () => {
const ctx = useContext(ExampleContext);
const history = useHistory();
const onChange = (ev: React.ChangeEvent<HTMLInputElement>) => {
ctx.text = ev.target.value;
};
return (
<div>
<form>
<input
type="text"
defaultValue={ctx.text}
onChange={(ev) => onChange(ev)}
/>
<button onClick={() => history.push(AppRoute.ctx2.path)}>submit</button>
</form>
</div>
);
};
Env |
Ver |
Jinja |
2.11.0 |
Python |
3.8.5 |
- 変数名[begin:end]で指定する
{% set some_variable = string_variable[0:100] %}
Env |
Ver |
Jinja |
2.11.0 |
Python |
3.8.5 |
- Jinja2でループ処理の中で変数の足しこみとかをするやつ
- 代入先の変数宣言は
{% set ns = namespace(title = "") %}
のようにしてやる必要がある
- 後はループの中で
set
してやれば上手くいく
- 変数は宣言したブロックがスコープになるので、スコープを広げたいときは適当にブロックを上げてやると良い
- MkDocsのテンプレートでパンくずリストを生成するコード
{% set ns = namespace(title = "") %}
{% for doc in page.ancestors %}
{% set ns.title = "[" + doc.title + "] " + ns.title %}
{% endfor %}
Env |
Ver |
Jinja |
2.11.0 |
Python |
3.8.5 |
─src
├─app
│ ├─configs
│ │ └config.yaml
│ ├─templates
│ │ └─main.html
│ └─__init__.py
└─main.py
from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
# appはフォルダ構成のappフォルダを指す
loader=PackageLoader('app', 'templates'),
autoescape=select_autoescape(['html', 'xml'])
)
template = env.get_template('main.html')
# `render()` の引数は埋め込み変数を KeyValue 形式で指定
print(template.render(the='variables', go='here'))
Env |
Ver |
Jinja |
2.11.0 |
Python |
3.8.5 |
─src
├─app
│ ├─configs
│ │ └config.yaml
│ ├─templates
│ │ └─main.html
│ └─__init__.py
└─main.py
from yaml import safe_load as yamlLoad
from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
loader=PackageLoader('app', 'templates'),
autoescape=select_autoescape(['html', 'xml'])
)
template = env.get_template('main.html')
with open('app/configs/config.yaml') as fYaml:
print(template.render(yamlLoad(fYaml)))